스프링 데이터 JPA가 제공하는 공통 인터페이스는 SimpleJpaRepository 클래스가 구현한다.
@Repository@Transactional(readOnly = true)public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> { @Transactional public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } } ...}
@Repository 적용 : JPA 예외를 스프링이 추상화한 예외로 변환한다.
@Transactional 트랜잭션 적용 : JPA의 모든 변경은 트랜잭션 안에서 이루어져야 한다.
스프링 데이터 JPA가 제공하는 공통 인터페이스를 사용하면 데이터를 변경(등록, 수정, 삭제)하는 메소드에 @Transactional로 트랜잭션 처리가 되어 있다. 따라서 서비스 계층에서 트랜잭션을 시작하지 않으면 리포지토리에서 트랜잭션을 시작한다.
서비스 계층에서 트랜잭션을 시작했으면 리포지토리도 해당 트랜잭션을 전파받아 그대로 사용한다.
@Transactional(readOnly = true) : 데이터를 조회하는 메소드에는 readOnly = true 옵션이 적용되어 있다.
데이터를 변경하지 않는 트랜잭션에서 readOnly = true 옵션을 사용하면 플러시를 생략해서 약간의 성능 향상을 얻을 수 있다.(15장 4.2 참고)
save() : 저장할 엔티티가 새로운 엔티티면 저장(persist)하고 이미 있는 엔티티면 병합(merge)한다.
새로운 엔티티를 판단하는 기본 전략은 엔티티의 식별자로 판단하는데 식별자가 객체일 때 null, 자바 기본 타입일 때 숫자 0 값이면 새로운 엔티티로 판단한다.
Persistable 인터페이스를 구현한 객체를 빈으로 등록하면 위의 조건을 직접 정의할 수 있다. java public interface Persistable<ID extends Serializable> extends Serializable{ ID getId(); boolean isNew(); }