[Japring-Study 5] spring-jdbc-1

Kim yohan·2024년 8월 12일

JapringStudy

목록 보기
5/12
post-thumbnail

spring-mvc 과제가 끝나고, 이번주 과제는 jdbc-1과 core-1,2이다.
jdbc에 대해 알아보자!!


Jdbc

데이터베이스 연결을 도와주는 JAVA의 API이다.
Jdbc가 있기 전에는 애플리케이션 서버가 DB와 직접 커넥션 연결하고, sql 날리고 했었다.

하지만, 여기엔 2가지 문제가 있었다.
1. DB가 바뀌면, 애플리케이션 서버의 코드도 바뀌어야한다.
2. DB가 바뀌면, 개발자가 새 DB 사용을 위한 지식을 새로 배워야한다.

그래서, 이를 해결하기 위해 Jdbc가 탄생했다.
Jdbc는 Java Database Connectivity의 약자로, db 연결을 위한 표준 인터페이스이다. 개발자는 db에 상관없이 Jdbc만 사용해서 개발하면 된다. 각 DB회사는 Jdbc 인터페이스를 구현하게 되고, 이를 'JDBC 드라이버'라고 한다.

public Member save(Member member) {

        String sql = "insert into member(name) values(?)";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DataSourceUtils.getConnection(dataSource);;
            pstmt = conn.prepareStatement(sql,
                    Statement.RETURN_GENERATED_KEYS);
            pstmt.setString(1, member.getName());
            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                member.setId(rs.getLong(1));
            } else {
                throw new SQLException("id 조회 실패");
            }
            return member;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
		}
    }
  • DataSourceUtils.getConnection(dataSource)
    • DriverManager.getConnection(..)을 호출한다.
    • DB 드라이버를 찾아서, 드라이버가 제공하는 커넥션을 반환해준다.
  • Statement
    • SQL 전달 담당
    • SQL Injection 공격을 막기 위해, parameter를 ?로 비워두고, 파라미터 바인딩 방식을 통해 따로 넣어준다. 그런 Statement를 PreparedStatement라고 한다.
  • ResultSet
    • SQL 결과 응답
  • close(..)
    • 리소스 누수 방지를 위해, finally를 통해 자원들을 무조건 close 해주어야 한다!
    • 커넥션 부족으로, 장애가 발생할 수 있다.

위 코드를 보면 알 수 있다시피, 코드가 매우 복잡하고, 메인 로직보다 DB연결을 위한 코드가 많다. 이 문제를 해결하기 위해 JdbcTemplate가 등장한다.



JdbcTemplate

Jdbc를 편하게 사용하기 위해, Spring이 제공하는 모듈이며, SQL Mapper이다. 따라서, 사용자는 sql만 사용할 줄 알면, 나머지 번거로운 일은 SQL Mapper가 대신 해준다.

public void insert(Customer customer) {
	String sql = "insert into customers (first_name, last_name) values (?, ?)";
	jdbcTemplate.update(sql, customer.getFirstName(), customer.getLastName());
}

장점

  1. try-catch, DB 커넥션을 위한 코드가 모두 사라져서, 사용자는 SQL 작성에만 집중할 수 있다.

  2. 트랜젝션 관리가 편하다!
    Jdbc에서는 트랜젝션을 시작하기 위해서, 아래 코드가 필요했다.

connection.setAutoCommit(false);
connection.commit();

하지만, JdbcTemplate에서는 @Transactional을 통한, 트랜젝션 관리가 가능하다.

  1. 객체 매핑이 편하다
    Jdbc에서는 rs.next()를 반복해, 객체에 매핑 시켜주어야한다. 단일 객체가 아니면, while을 통해 반복해야해서, 불편하고, 실수할 가능성이 높아진다.
    JdbcTemplate에선 RowMapper를 통해 편하게 객체 매핑을 할 수 있다.
List<Person> persons = jdbcTemplate.query("select * from mytable where id=1",
      (resultSet, i) -> new Person(
              resultSet.getInt("id"),
              resultSet.getString("name")
      ));
}


KeyHolder

쿼리 시, 자동 생성되는 키 값을 받기 위해 사용한다.
일반적으로 삽입(insert) 작업 시, 자동 생성되는 키 값을 받기 위해 사용한다고 한다.
효율적으로 키 값을 받아올 수 있다고 하는데, 내가 보기엔 너무 복잡해 보인다.

public Number insertAndGetId(String value1, String value2) {
        String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)";
        KeyHolder keyHolder = new GeneratedKeyHolder();

        jdbcTemplate.update(
            connection -> {
                PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                ps.setString(1, value1);
                ps.setString(2, value2);
                return ps;
            },
            keyHolder
        );

        return keyHolder.getKey(); // 생성된 키를 반환
    }
profile
꾸준히 성실하게

0개의 댓글