인프런 커뮤니티 질문&답변

asiazizon님의 프로필 이미지

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

persist에 대하여...

23.02.16 23:07 작성

·

367

1

안녕하세요. 공부하다 헷갈리는 부분이 있어서 질문드립니다.

제가 알기로는 persist를 실행을 해도 트랜잭션이 끝날 때 쿼리가 나가면서 insert가 되는 걸로

알고 있습니다.

그래서 아래 사진과 같은 테스트를 해봤습니다.

@Slf4j
@SpringBootTest
@Transactional
@Commit
class CategoryRepositoryImplTest {

    @Autowired
    CategoryRepository categoryRepository;

    @Autowired
    EntityManager em;

    @Test
    void save() {
        Category category = new Category("상의", 1, null);
        category.addDate(LocalDateTime.now(), LocalDateTime.now());
        em.persist(category);
        log.info("=================================");
    }
}

 

save를 실행해보았더니 로그가 아래와 같이 찍힙니다.

2023-02-16 22:43:53.648 DEBUG 8220 --- [ main] org.hibernate.SQL :

insert

into

t_category

(mod_date, reg_date, depth, name, parent_id)

values

(?, ?, ?, ?, ?)

2023-02-16 22:43:53.684 INFO 8220 --- [ main] s.s.r.c.CategoryRepositoryImplTest : =================================

 

persist를 날리면 메소드가 끝날 때 트랜잭션이 끝나기 때문에 insert쿼리가 로그보다 먼저 찍히면 안될 것 같은데 로그에는 그렇게 찍히니 조금 혼란스럽습니다.

현재 저 프로젝트는 jpa, spring data jpa, querydsl 를 같이 사용하고 있습니다.

왜 저렇게 동작되는지 원인을 알 수 있을까요?

혹시나 해서 관련된 테이블 category클래스와 dateColumn 클래스도 캡처하겠습니다.

@Entity
@Table(name = "T_CATEGORY")
@Getter
@NoArgsConstructor(access = PROTECTED)
public class Category extends DateColumns {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "CATEGORY_ID", nullable = false)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private Integer depth;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID")
    private Category parent;

    public Category(String name, Integer depth, Category parent) {
        this.name = name;
        this.depth = depth;
        if(depth > 1) {
            this.parent = parent;
        }
    }
}
@MappedSuperclass
@Getter
public class DateColumns {

    @Column(name = "REG_DATE", updatable = false, nullable = false)
    private LocalDateTime regDate;

    @Column(name = "MOD_DATE", nullable = false)
    private LocalDateTime modDate;

    public void addDate(LocalDateTime reg, LocalDateTime mod){
        regDate = reg;
        modDate = mod;
    }
}

답변 2

3

OR님의 프로필 이미지

2023. 02. 17. 13:01

안녕하세요,

em.persist 시 동작은 엔티티의 primary key 생성 전략(@GeneratedValue(strategy=xxx))에 따라 달라집니다.

  • GenerationType.IDENTITY

    • 기본 키 생성을 데이터베이스에 위임합니다.

    • 따라서 em.persist() 시점에 즉시 insert sql을 실행하고 db에서 식별자를 받아옵니다.

  • GenerationType.SEQUENCE

  • GenerationType.TABLE

3개 방식 중 아래의 2개 방식이 트랜잭션 시점에 실제 insert 쿼리를 발생 시키게 됩니다.

자세한 내용은 수업 "엔티티 매핑 | 기본 키 매핑"에 있습니다~

2

개발하는쿼카님의 프로필 이미지

2023. 02. 17. 14:58

안녕하세요^^

기본 키 매핑 전략 IDENTITY

  • IDENTITY 전략은 em.persist() 시점 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회합니다.

  • 영속성 컨텍스트에 관리되려면 PK가 무조건 있어야 하기 때문에 commitSQL이 날아가지 않습니다.

  • 따라서 em.persist()는 쓰기 지연 SQL 저장소를 사용할 수 없습니다.

 

감사합니다.^^