-
em.persist 이후 get$ObjsectId() 가 가능 한가?Java&Spring/Spring 2023. 2. 4. 17:46
코드를 보자
@Entity public class PrivateTodo { @Id @GeneratedValue @Column(name = "private_todo_id") //pk private Long id ; ....
<< primitive type : long 을 안쓰는 이유는 , Long 은 null 이 들어가지만 long 에는 null 이 불가능 하다. >>
-> id 에 null 이 들어가는 경우를 열어둔 것은 이글의 제목의 답이 될 수 있다.
Entity Manager 를 통해서 PrivateTodo의 객체를 DB 에 저장하는 코드이다.
@Repository @RequiredArgsConstructor public class PrivateTodoRepository { @Autowired private final EntityManager em; public PrivateTodo save(Member member ,String task,Date date) { PrivateTodo privateTodo = new PrivateTodo(); privateTodo.setMember(memeber); privateTodo.setTask(task); privateTodo.setDate(date); privateTodo.setComplete(false); privateTodo.setImageUrl("Default"); em.persist(privateTodo); // privateTodo.getId(); ?? 가능 ? return privateTodo; } }
질문 :
em.persist(privateTodo); 이후 return privateTodo , 반환값에는 객체의 id 가 있을까 ?
privateTodo.getId(); 가 바로 가능한가?
정답은 상황에 따라 있다 이다. 왜일까 ?
privateTodo 의 객체 생성시 @GeneratedValue ,@id 에 의하여 id 값이 정해진다.
조금 더 자세하게 보자.
1. Entity manager 의 persist 를 보자 , Object entity 를 받는다.
public void persist(Object entity); /** * Merge the state of the given entity into the * current persistence context. * @param entity entity instance * @return the managed instance that the state was merged to * @throws IllegalArgumentException if instance is not an * entity or is a removed entity * @throws TransactionRequiredException if there is no transaction when * invoked on a container-managed entity manager of that is of type * <code>PersistenceContextType.TRANSACTION</code> */
persist를 사용할거면 object entity 가 필요하다라는 것을 알 수있다.
entity 는 언제만들까?
코드 레포지토리의 save 메서드를 보면 privateTodo 라는 객체를 만든다.
PrivateTodo privateTodo = new PrivateTodo();
이는 비영속 상태 하단 그림의 (New) 이다.
->영속성 컨텍스트와 전혀 관계가 없는 상태이다.
EntityManger 즉 em.persist(privateTodo); 를 통해 우리는 영속성 컨텍스트에 저장을 하고 데이터 베이스에 객체를 저장한다.
즉 이글의 질문
"em.persist 이후 바로 get$ObjsectId() 가 가능 한가?" 는 당연 하게 "yes" 라는 대답을 하고 싶지만 실상은
"pk 생성 전략에 따라 달라진다" 가 맞다.
마지막으로 그럼 정확하게 언제 DB 테이블을 확인해서 새로운 객체의 id 값을 줄까? 라는 질문의 답은
@GenrationType 에 달려 있다.
//@GeneratedValue 은 GenerationType ,default 가 AUTO 이다. @GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.SEQUENCE) @GeneratedValue(strategy = GenerationType.TABLE)
기본 설정부터 보자.
1 .AUTO (가급적이면 피하자)
@GeneratedValue 의 strategy 의 default value 이다.
디비의 종류도 많고 데이터 베이스 마다 기본키 생성 전략도 다르다.
데이터베이스 마다 지원하는 서비스가 드른데 이를 데이터 베이스 방언(Dialect ) 라 부른다.
Auto 를 선택할시 사용하는 디비의 종류에 맞춰 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.
tip)
- 스키마 자동 생성 기능(ddl-auto)을 사용한다면, 하이버네이트가 기본값을 사용해서 적절하게 만들어준다, 알고 있자.
- Hibernate 5부터 MySQL에서의 GenerationType.AUTO는 IDENTITY가 아닌 TABLE을 기본 시퀀스 전략으로 가져간다.
2. IDENTITY
데이터 베이스에 위임을 하는 전략이다.
MySQL의 AUTO_INCREMENT 기능은 데이터베이스가 기본 키를 자동으로 생성해준다.
= AUTO_INCREMENT 는 데이터 베이스에 INSERT SQL을 실행 한 이후에ID 값을 알 수 있다.
이게 무슨 말인가??
당연하 사실 두가지를 적는다.
- 엔티티가 영속 상태가 되기 위해서는 식별자가 필수이다.
- JPA 는 보통 transaction 을 Commit 하는 시점에 INSERTSQL 이 날라간다.
= em.persist() 를 한다고 바로 DB 에서 commit 이 되는 것이 아니다.
그러나
"IDENTITY 전략에서는 em.persist()를 하는 즉시 INSERT SQL 을 실행하고 DB에서 식별자를 만든다."
- ID 값이 null 로 INSERT SQL 이 날라간다
- MYSQL 의 AUTO_INCREMENT 로 ID 가 자동 생성된다.
- 1차 캐시에 저장해 두기 위해 DB 에서 반환을 받는다. 이때 넘긴 객체는 영속 상태가 된다.
즉 다음 과 같은 코드에서 getId 가 정상 적으로 나오며, SELECT SQL 이 날라가지 않는다.
-> JDBC driver 에 insert 하고 바로 리텀 받는게 내부적으로 존재 한다 한다.
public PrivateTodo save(String task,Date date) { PrivateTodo privateTodo = new PrivateTodo(); ... privateTodo.setTask(task); privateTodo.setDate(date); .. em.persist(privateTodo); /// insert 이후 System.out.println(privateTodo.getId()); // 정상적으로 출력 됨 return privateTodo; }
3.SEQUENCE
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다
mysql 에서는 사용하지 않는다. 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용한다.
- > allocationSize로 한 번에 사용할 시퀀스 덩어리 사이즈를 정해서 최적화 할 수 있다.
4.TABLE
- 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략이다.
- 모든 데이터베이스에 적용 가능하나, 성능적인 손해가 있어서 잘 쓰지 않는다.
자 최종 정리이다.
- mysql
- @GeneratedValue(strategy = GenerationType.IDENTITY) 를 이용하면
em.persist()메서들 사용하는 순간 , Entity 가 DB 에 저장이되고 이때 1차 캐시에 @Id 를 저장한다.
이후 commit() 를 통해 최종적으로 저장을 한다.
감상 : "영속성을 이해하자"
참고 :
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
'Java&Spring > Spring' 카테고리의 다른 글
@RequiredArgsConsructor ,@NoArgsConstructor , @AllArgsConstructor (0) 2023.02.15 @RequiredArgsConstructor, @NotNull, @Valid ,@NotBlank (0) 2023.02.15 스프링부트 GCS 연동 part2 (0) 2023.01.26 스프링부트 GCS 연동 part1 (0) 2023.01.25 Spring data-JPA,data-Rest (feat.프로젝트 구조) (0) 2022.10.31