티스토리 뷰

 

테스트 환경

의존성

  • spring-boot-starter
  • spring-boot-starter-data-jpa
  • spring-boot-start-test
  • h2 database
plugins {
    id 'org.springframework.boot' version '2.7.2'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    runtimeOnly 'com.h2database:h2'
}

test {
    useJUnitPlatform()
}

 

 

관련 Class

  • Entity : Customer
  • Test class : PersistentceContextTest
// Test class
@DataJpaTest
class PersistenceContextTest {

    @PersistenceContext
    private EntityManager em;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    ...
    
    // DB 데이터 확인을 위한 메서드
    private List<Customer> getCustomersFromDb() {
    	final String sql = "SELECT * FROM customer";
    	List<Customer> customers2 = jdbcTemplate.query(sql,
            (resultSet, rowNum) -> new Customer(
                    resultSet.getLong("id"),
                    resultSet.getString("firstname"),
                    resultSet.getString("lastname")
            ));
    	return customers2;
    }
}

// Customer 
@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String firstname;
    private String lastname;

    public Customer() {
    }

    public Customer(String firstname, String lastname) {
        this(null, firstname, lastname);
    }

    public Customer(Long id, String firstname, String lastname) {
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public Long getId() {
        return id;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void updateName(String newFirstname, String newLastname) {
        this.firstname = newFirstname;
        this.lastname = newLastname;
    }
}

 

application.properties

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

 

 

영속 상태와 준영속 상태를 테스트 코드를 통해 확인해 보자

1) persist( ) - 객체를 영속화 

  • 영속 상태는 영속성 콘텍스트가 관리하는 객체를 의미
  • 객체를 영속화시키기 위해 persist 메서드를 활용
  • 영속성 콘텍스트가 관리한다고 해서 DB에 저장된다는 의미는 아님
  • 콘솔창에서 persist 메서드가 호출될 때 insert 쿼리가 실행되지 않는 것을 확인할 수 있음
    @Test
    void persist(){
        // 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        assertThat(em.contains(customer)).isFalse();

        // new -> Managed (영속성 컨텍스트가 관리하게됨)
        em.persist(customer);
        assertThat(em.contains(customer)).isTrue();

        // persist()로 Managed 상태가 되더라도 DB에는 저장되지 않음.
        List<Customer> customers = getCustomersFromDb();
        assertThat(customers).hasSize(0);
    }

 

 

2) flust( ) - 영속 상태에서 DB에 반영

  • flush를 통해 영속성 콘텍스트에 있는 객체를 DB에 저장 - insert query 수행
  • flush 전 후로 DB 조회 결과가 다른 것을 확인할 수 있음
  • flush 하더라도 영속성 컨텍스트에 해당 객체는 남아있음
    @Test
    void flush(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        // Managed (영속 상태)
        em.persist(customer);

        List<Customer> customers = getCustomersFromDb();

        // persist() 상태는 DB에 저장되지 않음
        assertThat(customers).hasSize(0);

        // flush() 로 인해 insert query 가 날라감
        em.flush();
        
        List<Customer> customers2 = getCustomersFromDb();
        assertThat(customers2).hasSize(1);
    }

 

 

3) detach( ) : 영속상태 → 준영속상태

  • 영속 상태였다가 준영속 상태가 되면 영속성 콘텍스트에서는 찾을 수 없음
  • 준영속 상태는 식별자(member.id)는 있지만 영속성 컨텍스트에서 찾을 수 없는 상태를 의미
    @Test
    void detach(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        // persist() 로 영속상태(영속성 컨텍스트에서 해당 객체를 들고 있음)
        em.persist(customer);
        assertThat(em.contains(customer)).isTrue();

        // 영속상태 -> 준영속 상태
        em.detach(customer);
        assertThat(em.contains(customer)).isFalse();
    }

 

4) merge( ) : 준영속상태 영속상태

  • 준영속 상태에서 다시 영속 상태로 변경하기 위해서는 merge 메서드를 활용
    @Test
    void merge(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        em.persist(customer); // 영속 상태
        em.flush(); // insert 쿼리 수행

        // 준영속 상태에서 객체 상태 변경 후 다시 영속상태를 만든다
        em.detach(customer); // 영속 -> 준영속
        customer.updateName("new firstname", "new lastname"); // 객체의 상태 변경
        em.merge(customer); // 준영속 -> 영속 상태

        em.flush(); // update 쿼리 수행
        List<Customer> customers = getCustomersFromDb();
        assertThat(customers.get(0).getFirstname()).isEqualTo("new firstname");
    }

 

5) remove( ) : 영속 -> 삭제

  • 영속 상태에서 삭제를 하기 위해서는 remove()를 사용
  • remove()만 호출한 경우 영속성 콘텍스트에서만 삭제
  • DB에도 삭제가 반영이 되려면 flush()를 해야 함
 @Test
    void remove(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        em.persist(customer); // 영속 상태
        em.flush(); // insert 쿼리 수행
        assertThat(em.contains(customer)).isTrue(); // 영속상태

        em.remove(customer); // Persistence Context에서 해당 객체 삭제, DB는 삭제 X
        List<Customer> customers = getCustomersFromDb();
      	
        // DB에 여전히 데이터가 있음
        assertThat(customers.get(0).getFirstname()).isEqualTo("firstname"); 
        assertThat(em.contains(customer)).isFalse(); // 영속상태가 아님

        em.flush(); // delete 쿼리 수행
        
        List<Customer> customers1 = getCustomersFromDb();
        assertThat(customers1).hasSize(0); // DB 데이터 삭제
    }

 

 

영속 상태와 준영속 상태에서 객체 상태 변경 시 DB 반영 여부

1) 준영속 상태에서 객체 상태 변경 

  • Update 쿼리를 수행하지 않음.
    @Test
    void detachAgainstPersist(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        em.persist(customer); // 영속상태
        em.flush(); // DB 저장

        em.detach(customer); // 준영속 상태
        customer.updateName("new firstname", "new lastname"); // 객체의 변경 update
        
        em.flush(); // flush()하더라도 update 쿼리가 날라가지 않음.(due to 준영속상태)

        List<Customer> customers = getCustomersFromDb();
        assertThat(customers.get(0).getFirstname()).isEqualTo("firstname");
    }

 

2) 영속 상태에서 객체 상태 변경 

  • Update 쿼리 수행
   @Test
    void persistAgainstDetach(){
    	// 객체 생성
        Customer customer = new Customer("firstname", "lastname");
        
        em.persist(customer); // 영속 상태
        em.flush(); // insert 쿼리 수행

        customer.updateName("new firstname", "new lastname");
        
        em.flush(); // update 쿼리 수행 (due to 영속상태)

        List<Customer> customers = getCustomersFromDb();
        assertThat(customers.get(0).getFirstname()).isEqualTo("new firstname");
    }

 

 

 

 

이상 전달 끝!

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함