Query query = entityManager.createQuery("SELECT e FROM User e WHERE e.username = :username");
query.setParameter("username", "홍길동");
List<User> results = query.getResultList();
@Transactional
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
새로운 Entity이면 persist()를 그게 아니면 merge()를 호출한다. (save 메서드를 호출하면 INSERT 또는 UPDATE가 자동으로 되는 이유가 이거다.)
@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {
Assert.notNull(entity, "Entity must not be null!");
if (entityInformation.isNew(entity)) {
return;
}
Class<?> type = ProxyUtils.getUserClass(entity);
T existing = (T) em.find(type, entityInformation.getId(entity));
// if the entity to be deleted doesn't exist, delete is a NOOP
if (existing == null) {
return;
}
em.remove(em.contains(entity) ? entity : em.merge(entity));
}
remove() 메서드를 사용한다.
트랜잭션이 종료될 때 DB에 반영된다.
Transaction Manager
JpaTransactionManager
JpaTransactionManager는 JPA(Java Persistence API)를 사용하여 Entity와 데이터베이스 간의 작업을 관리할 때 사용된다. EntityManager와 함께 작동하며, JPA 표준에 따른 트랜잭션 관리 기능을 제공한다.
EntityManagerFactory와 연결되어, JPA 영속성 컨텍스트를 관리한다.
EntityManager를 통해 데이터베이스와의 연결을 유지하며, 트랜잭션 경계 내에서 데이터를 관리한다.
DataSourceTransactionManager
DataSourceTransactionManager는 순수 JDBC 또는 MyBatis와 같은 프레임워크를 사용할 때 주로 사용된다.
DataSource와 직접 연결되어 JDBC 연결을 관리한다.
JDBC 기반의 트랜잭션 관리
DataSource를 사용하여 데이터베이스 연결을 직접 관리
JDBC 커넥션을 직접 사용하거나, MyBatis와 같은 ORM 프레임워크와 함께 사용할 때 적합
기본적으로, JpaTransactionManager는 JPA Entity Manager를 통해 트랜잭션을 관리한다.
하지만, JpaTransactionManager는 내부적으로 DataSource를 사용하여 트랜잭션을 처리하기 때문에, 이 DataSource를 MyBatis와 공유할 수 있다.
따라서, MyBatis를 사용할 때도 동일한 트랜잭션 컨텍스트에서 작업을 수행할 수 있다.
JPA와 MyBatis가 같은 데이터베이스에 대해 작업을 하고 있고, 동일한 트랜잭션 경계 내에서 두 프레임워크를 함께 사용하고자 한다면 JpaTransactionManager만 사용해도 된다
Spring Boot는 spring-boot-starter-data-jpa 의존성을 추가하면 자동으로 JpaTransactionManager를 구성하기때문에
별도로 Transaction Manager를 설정하지 않아도 된다.
JPA 영속성 컨텍스트로 관리되는 Entity를 MyBatis로 업데이트할 때 주의사항
JPA의 영속성 컨텍스트와 MyBatis의 분리된 상태
JPA의 영속성 컨텍스트는 Entity 객체를 관리한다. Entity가 영속성 컨텍스트에 포함되면, 해당 Entity의 상태는 영속성 컨텍스트에 의해 추적된다.
MyBatis로 데이터를 직접 업데이트하면, JPA는 해당 변경 사항을 인지하지 못한다. 즉, JPA의 영속성 컨텍스트에 있는 Entity와 데이터베이스의 상태가 불일치하게 됩니다.
변경 감지 실패
JPA는 Entity의 상태 변화를 자동으로 감지하고, flush() 시점에 데이터베이스에 반영한다.
MyBatis를 사용해 Entity를 직접 업데이트한 경우, JPA는 해당 Entity의 변경 사항을 모니터링할 수 없기 때문에, JPA가 관리하는 Entity가 여전히 이전 상태로 유지될 수 있다. 이는 예상치 못한 동작을 일으킬 수 있다.
JPA의 1차 캐시 문제
JPA는 Entity를 1차 캐시에 저장하여 데이터베이스와의 동기화 작업을 최소화한다. MyBatis로 데이터베이스를 업데이트하더라도 JPA의 1차 캐시는 여전히 이전 데이터를 참조하게 된다. 따라서, JPA를 통해 Entity를 다시 조회하면 변경된 데이터가 반영되지 않고, 이전 상태의 데이터가 반환될 수 있다.
JPA 영속성 컨텍스트에 의해 관리되는 Entity를 MyBatis로 업데이트하면, JPA의 영속성 컨텍스트와 데이터베이스 간의 상태 불일치가 발생할 수 있다. 따라서 이 경우에는 JPA와 MyBatis 간의 사용에 주의가 필요하며, 적절한 동기화 전략을 사용하는 것이 중요하다.
이제는 JPA Auditing 기능에 대해 알아보자.
JPA Auditing는 Entity의 변경 이력 관리에 필요한 기본적인 기능을 자동화하여 코드의 간결함과 유지보수성을 높이는 데 기여한다. 이를 통해 엔티티 생성과 수정 작업에 대해 일관성 있고 신뢰할 수 있는 이력을 관리할 수 있다.
댓글 영역