JPA

(JPA) JPA @Id GenerationType.AUTO, IDENTITY 차이

Developer RyanKim 2020. 7. 25. 02:30

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로 늘려주면 동작이 가능하였다.

 

참고:https://jaehun2841.github.io/2020/01/27/2020-01-27-hikaricp-maximum-pool-size-tuning/#%EC%9C%84%EC%97%90%EB%8A%94-%EC%98%88%EC%8B%9C%EC%9D%B4%EA%B3%A0-%EC%8B%A4%EC%A0%9C-%EC%83%81%ED%99%A9%EC%9D%80-%EB%AD%90%EC%98%80%EC%96%B4%EC%9A%94


* 추가