본문 바로가기

개발기술/ORM

Spring JPA 개념, 초기설정, Repository 인터페이스 구현

Persistence Framework

  • 데이터영속성(Persistence)이란 프로그램이 꺼져도 데이터는 사라지지 않는 것, 즉, 영구저장 DB를 사용하는 데이터를 말함. DB를 다루기 위해 필요한 프레임워크를 Persistence Framework라고 한다. 
  • Persistence Framework를 사용하면, DB관련되어 개발자가 공통적으로 작성하는 코드를 대신하여 동작시켜주어, 코드 재사용 및 유지보수에 용이하며 코드가 직관적이다.

대표적인 Persistaence Framework 역할

  • 1. DB연결관리 : MongoDB, Reddis, Mysql 등에 맞는 코드를 Framework가 대신 동작하여 DB에 종속적이지 않도록 해준다
  • 2. DB와의 연결상태에 따른 코드를 Framework가 대신 동작하여 DB의 연결에 대한 관리를 모두 if/else 그리고 try/catch문으로 대신 처리해줌
    • DB와 최초 연결시 DB연결 Fail Exception Handling
    • Query 실행시 Query동작 Fail Exception Handling
    • DB가 지속적으로 연결되어있는지 중간에 확인동작
    • DB연결이 끊겼을때 ExceptionHandling
    • DB사용이 끝나면 연결끊는 자원정리 동작
    • 트랜잭션관리

DB연결관리

public Connection getConnection() throws SQLException {
    String url = "jdbc:mysql://localhost:3306/mydb";
    String user = "root";
    String password = "mypassword";
    return DriverManager.getConnection(url, user, password);
}

 

Query 실행 및 예외 처리

try (Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {

        while (rs.next()) {
        System.out.println("User: " + rs.getString("name"));
        }
        } catch (SQLException e) {
        System.out.println("쿼리 실행 실패: " + e.getMessage());
        }

 

트랜잭션 관리

try (Connection conn = getConnection()) {
        conn.setAutoCommit(false); // 트랜잭션 시작

Statement stmt = conn.createStatement();
    stmt.executeUpdate("UPDATE users SET name='John' WHERE id=1");

    conn.commit(); // 변경사항 저장
} catch (SQLException e) {
        conn.rollback(); // 예외 발생 시 롤백
    System.out.println("트랜잭션 실패: " + e.getMessage());
        }

 

컨넥션 종료 및 리소스 정리

try (Connection conn = getConnection();
Statement stmt = conn.createStatement()) {

        stmt.executeUpdate("DELETE FROM users WHERE id=1");

} catch (SQLException e) {
        e.printStackTrace();
} finally {
        if (stmt != null) stmt.close(); // 명시적 리소스 해제
    if (conn != null) conn.close();
}

 

SQL mapper와 ORM

  • Persistence Framework는 SQL mapper와 ORM(Object Relation Mapping) 두종류가 있음.
  • SQL mapper는 DB에 따라서 SQL문을 수정해주어야해서 DB종속적인 반면 ORM은 프레임워크 자체적으로 sql문을 작성해주어 독립적임. 
    • SQL mapper는 개발자가 직접 sql쿼리문을 작성함
      • SQL mapper는 대표적으로 JDBC(Java Database Connectivity)가 존재
      • JDBC계층(Interface : Spring JDBC)는 Application 계층의 DAO와 Persistence계층의 DB사이를 매개하고,
    • ORM은 java의 Object를 db의 테이블과 직접 관계를 맺도록하여 sql문을 사용할 필요 없도록 함. 단, 복잡한 쿼리가 필요한 작업은 SQL작성이 필요할때가 있음.
      • ORM은 JPA(Java Persistent API)가 존재한다. 
      • JPA는 외부 라이브러리로 JDBC를 사용하는 API로 JDBC계층과 Application계층 사이에 위치한다.
      • 엄밀하게 말하면 JPA는 하나의 규약 및 표준이며 Hibernate는 JPA라는 규약을 따르는 프레임워크로써, JPA의 실질적 동작은 Hibernate에서 작동하고 있다.   

  

Persistence Context과 Entity Manager

  • JPA가 생성하는 Layer는 persistence context라 하며, EntityManager에 의해 관리된다.
  • Persistence context는 엔티티의 상태 변화를 추적하는 일종의 캐시 메모리로, 트랜잭션이 완료되기 전까지 데이터베이스에 직접 저장되지 않고 메모리에 저장된다
  • . 트랜잭션이 완료되면, persistence context에 저장된 변경 사항이 데이터베이스에 flush되어 반영되며, 이를 통해 트랜잭션 중 빈번한 데이터베이스 작업으로 인한 부하를 줄인다
  • 이러한 지연된 flush 메커니즘 때문에 트랜잭션이 끝나기 전까지 변경 사항이 데이터베이스에 반영되지 않으며, 다른 트랜잭션이 동일한 데이터를 조회할 때 이러한 변경 사항을 볼 수 없습니다. 그러나 flush 후에 데이터베이스에 새로운 레코드가 추가되거나 기존 레코드가 삭제되면, 다른 트랜잭션이 동일한 쿼리를 실행할 때 새로운 데이터가 나타나거나 기존 데이터가 사라지는 phantom read 현상이 발생할 수 있습니다.

JDBC방식으로 데이터 저장하기

1. gradle에 spring-jdbc와 mysql 라이브러리 추가하기 

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    runtimeOnly 'mysql:mysql-connector-java'

 

2. application.properties 설정파일에 DB접속정보 입력하기

gradle을 통해서 dependency(jdbc와 mysql-java)를 설정해두었기 때문에 spring property 설정이 가능함.

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://local:3306/project?serverTimezone=UTC\
  &characterEncoding=UTF-8
spring.datasource.username = root
spring.datasource.password =

 

JPA(ORM)방식으로 데이터 저장 설정하기

1.  gradle에 spring-jdbc와 mysql 라이브러리 추가하기

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java:8.0.33' // 버전 명시

 

2.application.properties 설정파일에 DB접속정보 외 JPA설정 추가하기

- 자동생성 SQL쿼리문 보여주기

- 데이터베이스 mysql로 고지하기

spring.jpa.show-sql=true 
spring.jpa.database=mysql

 

Repository 인터페이스 생성

  JpaRepository를 상속하는 추상클래스를 만들고 이를 빈으로 등록하기 위해서 @Repository로 표기해줌. JpaRepository의 generics값은 <Repository의 Entity, PK타입>을 기입해주면 됨. 

  원리는 인터페이스가 생성되면 Spring Data JPA는 인터페이스로 호출된 method call을 dynamic proxy(런타임에 인터페이스를 구현한 클래스를 생성)를 통해서 repository의 method call을 인터셉트하여, 클래스에서 method call을 하이버네이트에 의뢰하여 SQL쿼리를 생성해주는 방식임.

 해당 인터페이스에서 메소드를 정의하면 Repository extention에 의해서 메소드 이름에 걸맞도록 sql문이 생성된다. 그외에도 @Query("sql쿼리문")과 같이 sql쿼리를 직접 커스터마이징한 메소드를 생성할 수 있다.

@Repository
public interface JpaMemoryRepository extends JpaRepository<Memo,Integer> {
}
@Query("SELECT u FROM User u WHERE u.email = ?1")
User findByEmail(String email);