작성
·
458
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
안녕하세요,
em.persist 시 동작은 엔티티의 primary key 생성 전략(@GeneratedValue(strategy=xxx))에 따라 달라집니다.
GenerationType.IDENTITY
기본 키 생성을 데이터베이스에 위임합니다.
따라서 em.persist() 시점에 즉시 insert sql을 실행하고 db에서 식별자를 받아옵니다.
GenerationType.SEQUENCE
GenerationType.TABLE
3개 방식 중 아래의 2개 방식이 트랜잭션 시점에 실제 insert 쿼리를 발생 시키게 됩니다.
자세한 내용은 수업 "엔티티 매핑 | 기본 키 매핑"에 있습니다~
2
안녕하세요^^
기본 키 매핑 전략 IDENTITY
IDENTITY 전략은 em.persist() 시점 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회합니다.
영속성 컨텍스트에 관리되려면 PK가 무조건 있어야 하기 때문에 commit에 SQL이 날아가지 않습니다.
따라서 em.persist()는 쓰기 지연 SQL 저장소를 사용할 수 없습니다.
감사합니다.^^