몬그로이

데이터베이스Driver >> JDBCTemplate 본문

Organizing Docs/Java Docs

데이터베이스Driver >> JDBCTemplate

Mon Groy 2024. 6. 26. 20:00

데이터 베이스 Driver

역할: 애플리케이션과 데이터베이스 간의 통신을 중개

 

동작 방식 - Driver Manager 를 통하여 진행

1. 연결초기화 (Connection)

  • Driver Manager : getConnection()
    • 요청 수신 : 애플리케이션이 드라이버에 연결 요청한 것을 받음
    • 연결 설정 : 서버에 로그인 후 필요 설정 수행하여 연결 완료 (네트워크 정보, 인증 자격 증명 등 사용)

2. SQL 전송 및 실행 (Statement)

  • (준비된 sql문)
  • Driver Manager :  connection.statement(sql) 를 통해 statement 로 만들기
    • SQL 명령 변환 : 애플리케이션에서 보낸 SQL 명령을 DB가 이해하는 형태로 변환
  •  Driver Manager :  statement.execute() 으로 실행시키기 
    • 명령 처리 : 변환한 명령을 DB로 전송 (이 때 DB 는 쿼리를 처리하고 요구 받은 데이터를 검색하거나 변환시킴)
    • (참고 : preparestatement.excute() 도 가능)
    • (참고) CREATE/INSERT/UPDATE/DELETE 인 경우해당 -> SELECT인 경우는 executeQuery()
      더보기
      ** INSERT 문의 경우 집어넣기만 하면 되니까 execute() 로 끝나지만
      SELECT문의 경우는 꺼내서 보여줘야 하기때문에 executeQuery() 를 통해 객체를 꺼내는 메서드를 써야함
      두 경우 모두 반복문이 필요할 수는 있음 - 여러 개 저장할때, 여러개 출력할 때 - 상황에 따라 사용

3. 결과 처리 (Resultset)

  • 결과 수신 : DB에서 받은 결과물을 애플리케이션이 해석할 수 있는 형태로 변환 (필요한 경우 반복 : next())
  • 결과 전달 : 변환한 결과물을 애플리케이션에 전달
  • Driver Manager : 필요한 경우 next() 또는 getXxx() 사용

4. 연결 종료

  • Driver Manager : close()
    • 연결 해제 : 위 작업들이 끝난 후 DB 서버와의 연결 종료, 시스템 초기화

String insertSql = "INSERT INTO USERS (username) VALUES ('kim')";

try (PreparedStatement statement = connection.prepareStatement(insertSql)) {

      statement.execute();

} // execute () 에 의해 SQL 문을 "실행"  -> 따라서 executeUpdate()  오지 않아도 SQL 문에 따라서 작동함(INSERT됨)


prepareStatement 사용

* prepareStatement 는 Statement 를 상속하고 있는 Interface

Statement 는 executeQuery() 나 executeUpdate() 를 실행하는 시점에 파라미터로 sql 문을 전달하는데 반해

PreparedStatement 는 일단 sql 문을 parse 하여 결과를 캐싱 하므로 이후 같은 sql문을 수행할 때는 나머지 3단계만 수행하면 된

 

"캐싱"은 SQL 문이 처음 실행될 때 수행되는 구문 분석(parsing) 단계의 결과를 저장해두고, 이후 동일한 SQL 문이 실행될 때 구문 분석 과정을 생략하고 바로 나머지 단계들만 수행하는 것

더보기

Statement 의 4단계

구문분석 (parse) : 문법 검사, 의미 검사, 권한 검사, 실행 계획

치환 (bind) : 값을 입력 받아 변수 선언

실행 (execute) : 디스크에서 블록을 찾아 버퍼에 복사

인출 (patch) : 블록에서 원하는 데이터 추출

statement 방식 1

String selectSql = "SELECT * FROM USERS";

try (Statement statement = connection.createStatement()) {

      var rs = statement.executeQuery(selectSql);  //이하 생략

}

 

preparedStatement 방식 1

String selectSql = "SELECT * FROM USERS";

try (PreparedStatement statement = connection.prepareStatement(selectSql)) {

      var rs = statement.executeQuery(); //이하 생략

}

 

statement 방식 2 

String sqldb = "SELECT name, age FROM TABLE WHERE userID = " + userID;

Statement stmt = conn.createdateStatement();

ResultSet rst = stmt.executeQuery(sqlstr);

 

preparedStatement 방식 2

String sqldb = "SELECT name, age FROM TABLE WHERE userID = ? ";

PreparedStatement stmt = conn.prepareStatement(sqldb);

pstmt.setInt(1, userID);

ResultSet rst = pstmt.executeQuery();

 


JDBC 로 직접 SQL 작성시 문제점을 해결하기 위해

"Persistence Framework 등장"

더보기

JDBC 로 직접 SQL 작성시 문제점

  • SQL 쿼리 요청시 중복 코드 발생
  • DB별 예외에 대한 구분 없이 Checked Exception (SQL Exception) 처리
  • Connection, Statement 등.. 자원 관리를 따로 해줘야함 (자원 해제 안해주면 메모리 꽉차서 서버 다운)

1. SQL Mapper  인 JDBC Template 와 MyBatis 

JDBC Template

SQL을 직접 작성하여 사용

코드의 반복을 줄이고 예외처리를 일관되게 하는 등의 편리성이 추가된 것

SQL Mapper의 기본적인 형태

주로 개발자가 SQL 을 제어하고, 반복 작업을 줄이는 데 중점을 둠

 

MyBatis

더 진보된 SQL Mapper 프레임워크

SQL 을 XML 파일이나 어노테이션을 사용하여 매핑함

복잡한 객체(Object) 매핑도 지원하며

SQL 쿼리를 코드 외부로 분리하여 관리에 용이성이 높음

어노테이션 방식으로 사용할 경우
@Select("SELECT * FROM users WHERE id = #{id}") User selectUserById(int id);

매퍼방식으로 사용할 경우 (xml 파일 내부에 적어둔다)
<select id="selectUserById" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select>
더보기

어노테이션 예

@Mapper

@Select @Insert @Update @Delete

@Result @Results

@Param

2. ORM : JPA, Hibernate

ORM (Object-Relational Mapping) 

객체지향 프로그래밍 언어의 객체와 관계형 데이터베이스의 테이블 간의 매핑을 자동화하는 기술

SQL을 직접 작성하지 않고, 객체지향 방식으로 데이터 처리 가능

SQL에 종속되지 않으므로 DB를 교체할 때 코드 변경이 최소화 됨

지연로딩을 통해 성틍 최적화

 

JPA (Java Persistence API)

자바 EE의 일부로, 인터페이스와 애노테이션을 정의하여 ORM 을 표준화 함(표준 API)

Entity 클래스에 어노테이션을 사용하여 DB Table 과의 매핑 설정

SQL을 직접 작성하지 않고, 객체를 사용하여 DB작업 수행

JPA는 인터페이스이므로, 구현체(Hibernate, EclipseLink) 를 사용하여 동작

더보기

JPA 의 주요 인터페이스

Entity Manager : Entity 관리, DB 연산 수행 주체

EntityTransaction: 트랜젝션 관리

Query: 쿼리 생성 및 실행

Hibernate

JPA 구현체 중 하나 JPA 표준을 구현하면서도 추가적 기능을 제공하여 더욱 강력한 ORM 기능을 제공함

JPA 에 없는 기능 : 캐싱, 페이징, 고급 조회 방법

객체 지향 쿼리 언어인 HQL(Hibernate Query Language) 를 사용하여

SQL 과 유사하지만 객체를 대상으로 쿼리를 작성할 수 있음

*또는 JPQL(Java Persistence Query Language)을 사용하기도 하며, 복잡한 경우 @Query 어노테이션을 이용함

어노테이션 뿐만아니라 XML 을 사용한 매핑도 지원

더보기

Hibernate 의 주요 특징

엔티티 클래스에 따라 자동 스키마 생성

1차 캐시와 2차 캐시를 사용하여 성능 최적화

복잡한 객체 관계를 쉽게 매핑, 관리 가능

.

더보기

@Query 어노테이션 이용

 

일반인 SQL 사용 방식

@Query("SELECT u FROM User u WHERE u.username = :username")

 

네이티브 SQL 사용시 (주로 더 복잡한 Query를 작성할 경우 nativeQuery 를 사용하며, 끝에 표기함)

@Query(value = "SELECT * FROM users WHERE username = :username", nativeQuery = true)


 

JdbcTemplate 도입

JDBC 를 추상화한 Spring의 클래

DataSource 설정과 함께 JdbcTemplate 를 사용하여 JDBC 코드 간소화

효과 : 자동 DB 연결 구성, DataAccessException 으로 예외 체계 통일

RowMapper 와 함께 사용 (RowMapper 는  ResultSet의 각 행을 객체로 매핑하는 역할을 함)

 

예 : User 라는 클래스 정의 -> 테이블 생성되어 여러 user 가 테이블에 들어 있을 때

RowMapper<User> 를 상속한 RowMapper에 구현하여 사용하면

User 테이블에 있는 각 Row를 User 라는 객체로 매핑할 수 있도록 해줌

 

구현 예시

public class UserRowMapper implements RowMapper<User> {

 

    @Override

    public User mapRow(ResultSet rs, int rowNum) throws SQLException {

        User user = new User();

        user.setId(rs.getInt("id"));

        user.setUsername(rs.getString("username"));

        return user;

    }

}

 

인터페이스 RowMapper 

public interface RowMapper<T> {

T mapRow(ResultSet rs, int rowNum) throws SQLException;

}

 

사용 예시

@Autowired

private JdbcTemplate jdbcTemplate;

 

public List<User> getAllUsers() {

String sql = "SELECT id, username FROM USERS";

return jdbcTemplate.query(sql, new UserRowMapper()); //SQL 문을 바로 넣어도 됨

}

 


JdbcTemplate .method() 사용  : Query 문 타입

template.execute : CREATE

template .update : INSERT, UPDATE, DELETE 

template .queryForObject : SELECT

*DB에 접근하는 것이므로 Repository 에 JdbcTemplate 을 DI 후 메서드를 정의해 놓을 때 사용함


JDBCTemplate 사용과 Hibernate 의 @Query 사용의 차이

 

1. 목적과 방식

JDBCTemplate

직접 SQL 쿼리를 작성하여 데이터베이스에 접근

SQL 쿼리를 문자열로 작성, 매개변수를 전달하여 데이터베이스와 상호작용

보통 데이터베이스와 직접적인 접근을 필요로 하는 경우에 사용

 

Hibernate 의 @Query

JPQL(Java Persistence Query Language)이나 네이티브 SQL 쿼리를 사용하여 데이터베이스에 접근할 수 있도록 함

주로 엔티티 클래스의 메서드에 적용

 

 

2. 안정성

JDBCTemplate

SQL 쿼리를 문자열로 작성하므로 컴파일 시점에 문법적 오류를 잡기 어려움

 

Hibernate 의 @Query

JPQL을 사용할 경우 객체와 필드명을 기반으로 쿼리를 작성하므로 타입 안정성이 높음

컴파일 시점에 잘못된 필드명이나 타입 오류 등을 잡을 수 있음

 

 

3. ORM 기능

JDBCTemplate

순수 JDBC 코드를 사용하기 때문에 객체-관계 매핑 기능이 제한적

객체를 데이터베이스에 저장하거나 조회할 때는 직접 매핑해야 

 

Hibernate 의 @Query

객체와 데이터베이스 간의 매핑을 자동으로 처리

 

 

4. 사용 및 관리

JDBCTemplate

JDBC의 다양한 기능을 활용할 수 있으나

데이터베이스 트랜잭션 관리나 예외 처리 등을 개발자가 직접 해야함

 

Hibernate 의 @Query

Hibernate는 세션 관리와 영속성 컨텍스트를 통해 객체 상태를 추적하고 관리해주므로

트랜잭션 관리나 캐싱, 지연 로딩 등의 기능을 개발자가 직접 구현할 필요가 없음

 

 

 

 

 

 

'Organizing Docs > Java Docs' 카테고리의 다른 글

페이징  (0) 2024.06.28
MyBatis  (0) 2024.06.27
자바의 정석 6. 객체지향 프로그래밍1  (1) 2024.06.19
자바의 정석 5. 배열(Array)  (0) 2024.06.18
쓰기 지연 저장소와 지연 로딩  (0) 2024.06.04