본문 바로가기
ORM/Spring Data JPA

기본 CRUD - Create & Update

by 코딩하는 랄로 2024. 1. 16.
728x90

Create

Create는 CRUD에서 데이터를 생성하는 것을 담당한다. 그렇다면 JPA에서 Create는 무엇을 의미할까? JPA에서 Create는 일반 자바 객체가 Entity Manage에 의해 관리되는 Entity 객체로 변환되어 관리되는, 즉 영속화되었음을 의미한다.

 

Entity Manager에 의해 관리된다는 것은 일반 자바 객체가 영속성 컨텍스트에 포함, 저장되는 것이기 때문에 Create 관련된 메소드는 모두 save라는 이름으로 시작된다.

 

save(Entity)

메소드를 테스트하기 전에, 이전에 작업해두었던 Test 클래스에서 @BeforeEach는 없애도록 하자. ( 메소드 테스트를 위한 기본 설정은 다음 글 참고 : 바로가기 )

 

save 메소드는 Entity 타입의 자바 객체를 매개변수로 받아서 해당 객체를 영속화하여 반환한다. ( 반환하는 객체와 매개변수로 넘겨준 객체의 주소가 같기 때문에 반환한 객체를 따로 저장해주지 않아도 됨 )

@Test
void test() {
    // 일반 Student 객체
    Student student = new Student("kim", "email@email.com");
    System.out.println("save 전 : " + student.getId());
    
    studentRepository.save(student);
    
    // save 후, 영속화된 객체
    System.out.println("save 후 : " + student.getId());
}

 

코드를 동작시켜보면 아래와 같이 insert문을 실행하는 것을 볼 수 있다.

save 전 : null

Hibernate:
  insert
  into
    Student
    (address,name)
  values
    (?,?)

save 후 : 1

 

위의 결과를 토대로, 자바 객체가 영속화된다는 의미에 대해서 유추할 수 있다. ( 이전 글에도 몇 번 언급되긴 했지만 ) 자바 객체가 save 메소드를 통해 영속화가 되게 되면, 기존의 null 값이었던 ID 값이 할당된 것을 알 수 있다. 즉, JPA는 ID 값의 null 유무에 따라 영속화된 객체인지 아닌지를 인지하는 것이다.

 

saveAll(Iterable<Entity>)

Entity 타입을 가지는 Iterable 객체를 넘겨주어 여러개의 데이터를 저장할 수 있는 메소드이다. 반환값은 영속화된 객체를 리스트로 값는 List<Entity> 이다.

@Test
void test() {
    Student student1 = new Student("kim", "email@email.com");
    Student student2 = new Student("lee", "email@email.com");
        
    studentRepository.saveAll(List.of(student1, student2));

    studentRepository.findAll().forEach(System.out::println);
}

 

코드를 동작시키면 아래와 같이 각각의 데이터를 하나 하나 insert 문을 통해 저장하는 것을 알 수 있다.

Hibernate: insert into Student (address,name) values (?,?)
Hibernate: insert into Student (address,name) values (?,?)

Hibernate: select s1_0.id, s1_0.address, s1_0.name from Student s1_0 => findAll()
Student(id=1, name=kim, address=email@email.com)
Student(id=2, name=lee, address=email@email.com)

 

 

 

Update

JPA에 Update 를 위한 메소드는 Create의 메소드와 똑같다!! 이게 무슨 소리인지 이해하기 전에 먼저 예제 코드를 먼저 실행시켜보고 결과를 보자.

@Test
void test() {
    Student student1 = new Student("kim", "email@email.com");
    studentRepository.save(student1);

    // 영속화된 객체에 변경 발생
    student1.setName("lee");
    // 다시 저장??
    studentRepository.save(student1);
}

 

코드만 보면, 그냥 변경해서 다시 저장하는 것으로 밖에 안 보인다... 하지만 코드를 돌려보면 아래와 같이 신기한 결과를 마주할 수 있다.

첫번째 save =>
Hibernate: insert into Student (address,name) values (?,?)

두번째 save =>
Hibernate: select s1_0.id, s1_0.address, s1_0.name from Student s1_0 where s1_0.id=?
Hibernate: update Student set address=?, name=? where id=?

 

두번째 save에는 select문을 통해서 데이터를 가져온 다음 update 문을 동작시키는 것을 볼 수 있다. 두 개의 save에 모두 같은 주소를 참조하고 있는 객체를 넘겨주었지만 첫번째 save는 insert 문을 동작시키고 두번째 save는 update 문을 동작시켰다. 어떻게 이것이 가능할까?

 

이것이 가능한 이유는 두번째 객체가 영속화된 객체, 즉 Id 값이 null이 아닌 객체이기 때문에다. JPA는 영속화된 객체를 save 할 경우에 해당 id 값을 가지는 data가 존재하는지 확인한 후에, 존재하면 update문을 자동으로 실행시키는 것이다!! ( 더 구체적으로는, 해당 id를 가지는 데이터의 변경이 발견되면!! )

 

이러한 동작 방식을 가지고 있기 때문에, Create와 Update가 같은 메소드를 사용한다.

 

 

 

데이터베이스에 즉각 반영하기

JPA는 내부적으로 Entity Manager가 관리하는 Entity 객체를 영속성 컨텍스트에 담아두고 JDBC는 영속성 컨텍스트와 DB를 연결하여 데이터를 다룬다.

 

여기서 주의할 점은, Entity 객체가 추가되거나, 변경되었을 때 영속성 컨텍스트를 거쳐서 DB에 저장되게 되는데 이 때 약간의 텀이 생기게 된다. 즉각적으로 데이터베이스의 저장되거나 변경 사항이 적용되는 것이 아니다!!

 

그렇기 때문에 어떤 객체가 영속성 컨텍스트에 담기고, DB 에 반영되기 전에 영속화된 객체에 변화가 발생하게 되어 예상하지 못한 데이터가 DB에 담기는 상황이 발생할 수 있게 된다.

 

이러한 상황을 방지하고자 JPA는 기존의 save 메소드에 DB에 즉각적으로 반영하는 flush 동작을 추가한 메소드를 제공한다.

 

saveAndFlush(), saveAllAndFlush(Iterable<Entity)

사용방법은 기존의 메소드와 똑같다!!!

@Test
void test() {
    Student student1 = new Student("kim", "email@email.com");
    studentRepository.saveAndFlush(student1);  // INSERT

    Student student2 = new Student("lee", "email@email.com");
    student2.setId(1L);

    studentRepository.saveAndFlush(student2);  // UPDATE
}

 

실행하는 쿼리문도 기존의 메소드와 똑같다.

첫번째 save =>
Hibernate: insert into Student (address,name) values (?,?)

두번째 save =>
Hibernate: select s1_0.id, s1_0.address, s1_0.name from Student s1_0 where s1_0.id=?
Hibernate: update Student set address=?, name=? where id=?

 

728x90

'ORM > Spring Data JPA' 카테고리의 다른 글

EntityListener 다루기  (0) 2024.01.18
JPA Auditing  (1) 2024.01.17
기본 CRUD - DELETE  (1) 2024.01.16
기본 CRUD - READ  (0) 2024.01.16
JPA Repository - 개념  (0) 2024.01.15