(JPA) JPA @Id GenerationType.AUTO, IDENTITY 차이
JPA @Id @GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.IDENTITY) 차이
- 테스트용 Entity
@Data
@Entity
@Table(name = "ex_entity")
public class ExEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO) // or GenerationType.IDENTITY
private Integer id;
@Column(name = "name")
private String name;
}
- 테스트 코드
/**
* Developer : ryan kim
* Date : 2020-07-25
*/
@SpringBootTest
class ExEntityRepositoryTest {
@Autowired
ExEntityRepository repository;
@Test
public void autoIncrement_save_UsingSelectQuery() {
final int repeatCnt = 3;
for(int i = 0; i < repeatCnt; i++) {
ExEntity saved = new ExEntity();
saved.setName("name" + i);
repository.save(saved);
}
List<ExEntity> res = repository.findAll();
Assert.assertEquals(repeatCnt, res.size());
}
}
: repeatCnt 값 만큼 반복해서 entity를 생성하여 insert 한다.
@GeneratedValue(strategy = GenerationType.AUTO) (Default)
- 실행결과
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into ex_entity (name, id) values (?, ?)
2020-07-25 01:37:57.283 TRACE 4749 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [name0]
2020-07-25 01:37:57.283 TRACE 4749 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [1]
: insert 쿼리 전에 hibernate_sequence 테이블의 데이터에 대해서 select, update 쿼리가 실행된것을 확인 할 수 있다.
id 생성을 위해 hibernate_sequence 테이블의 시퀀스 값을 가져와 업데이트하고, 그 값으로 id를 생성하여 insert 쿼리를 사용한다.
이 설정이 @Id @GeneratedValue default로 동작한다.
: hibernate_sequence 테이블 및 next_val 컬럼 값 확인
@GeneratedValue(strategy = GenerationType.IDENTITY)
- 실행결과
Hibernate: insert into ex_entity (name) values (?)
2020-07-25 01:48:23.224 TRACE 4873 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [name0]
: insert 쿼리가 pk 값 없이 수행된다.
: 데이터베이스의 auto_increment 동작이 수행된다.
: ddl-auto: create 을 사용중이라면 pk 옵션이 auto_increment로 생성된다.
* 추가 maximum-pool-size 설정 시 주의사항
spring.jpa.datasource.hikari.maximum-pool-size= 1 설정
repeatCnt=3
- @GeneratedValue(strategy = GenerationType.AUTO) 경우 테스트
org.springframework.dao.DataAccessResourceFailureException: unable to obtain isolated JDBC connection; nested exception is org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection
Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30007ms.
: Connection 을 가져올 수 없어 Timeout이 발생한다.
- @GeneratedValue(strategy = GenerationType.IDENTITY) 경우 테스트
: 수행 성공. 심지어 repeatCnt=50 으로 테스트해도 문제없다.
GenerationType.AUTO 가 수행에 실패한 이유
GenerationType.AUTO를 사용할 경우 save() 수행시 insert 쿼리 전에 select, update 쿼리가 사용되는데 이 때 별도의 트랜잭션을 사용하여 추가적인 Connection을 사용하게 된다.
트랜잭션 끝나기 전까지 Connection이 반납되지 않기 때문에 계속 기다리는 DeadLock이 발생한 것이다.
(Transaction 용 Connection 1개 + repository.save()에 필요한 Connection 1개)
pool size를 2로 늘려주면 동작이 가능하였다.
* 추가