2.4 JPA
- Java Persistent API의 약자로 EJB 3.0과 함꼐 등장한 JavaEE와 JavaSE를 위한 영속성 관리와 O/R 매핑을 위한 표준 기술
- 오브젝트를 중심으로 개발하는 자바 같은 언어를 통해 접근하려면 불편한 점이 많았음
- ORM이란 오브젝트와 RDB 사이에 존재하는 개념과 접근 방법, 성격의 차이 떄문에 요구되는 불편한 작업을 제거
- 오브젝트를 가지고 정보를 다루면 ORM 프레임워크가 이를 RDB에 적절한 형태로 변환해주거나 그 반대로 RDB에 저장되어 있는 정보를 자바오브젝트가 다루기 쉬운 형태로 변환해주는 기술
- ORM을 사용하는 개발자는 모든 데이터를 오브젝트 관점으로 생각
- 가장 믾이 사용되는 대표적인 JPA 구현 제품들
- JBoss의 하이버네이트
- 아파치 OpenJPA
- 이클립스 EclipseLink
- 오라클 TopLink Essentionals
2.4.1 EntityManagerFactory 등록
- JPA Persistence Context에 접근하고 엔티티 인스턴스를 관리하려면 JPA의 핵심 인터페이스인 EntityManager를 구현한 오브젝트가 필요
- EntityManager는 JPA에서 두가지 방식으로 관리
- 애플리케이션이 관리하는 EntityManager
- JavaEE와 JavaSE에서 모두 사용 가능
- 컨테이너가 관리하는 EntityManager
- JavaEE 환경과 서버가 필요
- 애플리케이션이 관리하는 EntityManager
- 반드시 EntityManagerFactory를 빈으로 등록해줘야 함
LocalEntityManagerFactoryBean
- JPA 스펙의 JavaSE 기동 방식을 이용해 EntityManagerFactory를 생성
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" />
- 이 빈은
PersistentProvider
자동 감지 기능을 이용해 프로바이더를 찾고META-INF/persistence.xml
에 담긴 정보를 활용해EntityManagerFactory
를 생성
- 이 방식은 JPA만을 사용하는 단순한 환경에서 적용 가능하지만 스프링에서 본격적으로 사용하기에는 많은 제약사항이 발생
- 가장 큰 단점은 스프링의 빈으로 등록한 DataSource를 사용 못함
- 스프링이 제공하는 바이트코드 위빙 기법도 적용할 수 없음
- 실전에서 이 방법을 사용하는건 좋지 않음
JavaEE 5 서버가 제공하는 EntityManagerFactory
- JPA는 JavaSE 환경보다는 JavaEE에서 서버가 제공하는 JPA 프로바이더를 통해 사용하는 것이 일반적인 방법
- 스프링에선 JNDI를 통해 서버가 제공하는 EntityManager와 EntityFactory를 제공 받음
- 서버의 JTA를 이용해 트랜젹솬 관리 기능을 활용
- 이 방식은 JPA를 지원하는 JavaEE 5이상의 서버에 배치하고 JPA 프로바이더와 서버가 요구하는 설정을 해뒀다고 전제
- 모든 JPA 기능은 서버와 JPA 퍼시스턴스 유닛 설정을 따름
<jee:jndi-lookup id="emf" jndi-name="persistence/myPersistenceUnit" />
- jndi-name은 JNDI로 등록된 퍼시스턴스 유닛의 이름을 지정
LocalContainerEntityManagerFactoryBean
- 스프링이 직접 제공하는 컨테이너 관리 EntityManager를 위한 EntityManagerFatocy를 생성
- JavaEE 서버에 배치하지 않아도 컨테이너에서 동작하는 JPA 기능 활용 가능
- 스프링이 제공하는 일관성 있는 데이터 액세스 기술 접근 방법도 적용 가능
- 스프링의 JPA 확장 기능도 활용
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
- 이 빈은 META-INF/persistence.xml을 참고해 퍼시스턴스 유닛과 이를 활용하는 EntityManagerFactory를 생성
- DB 연결정보는 persistence.xml 프로퍼티에 등록하지 않아도 됌
- 대신 스프링에 빈으로 DataSource를 JPA에서 사용
- META-INF/persistence.xml 파일 예시
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd" version="2.0"> <persistence-unit name="default"> <class>springbook.learningtest.spring.jpa.Member</class> <exclude-unlisted-classes /> <properties> <property name="eclipselink.waving" value="false" /> </properties> </persistence-unit> </persistence>
- 일부 프로퍼티 설정은 JPA 구현 제품마다 다름을 주의
- 자바오브젝트와 RDB 테이블 사이의 매핑과 변환을 위한 정보는 orm.xml과 같은 매핑 정보를 담은 파일에 정의하거나 애노테이션을 이용해 클래스 안에 정의 가능
@Entity public class Member { @Id int id; @Column(length=100) String name; @Column(nullable=false) double point; // 수정자(setter), 접근자(getter) ... }
- LocalContainerEntityManagerFactoryBean에는 dataSource 외에 다음과 같은 프로퍼티 추가가 가능
persistenceUnitName
- persistence.xml에는 하나 이상의 퍼시스턴스 유닛이 정의될 수 있음
- persistence.xml에 다음과 같이 퍼시스턴스 유닛이 정의되어 있고, 이 설정을 따라 EntityManagerFactory 빈을 정의해야한다면 아래와 같이 추가
<!--persistence.xml--> <persistence-unit name="subPersistenceUnit"> <!-- LocalContainerEntityManagerFactoryBean --> <property name="persistenceUnitName" value="subPersistenceUnit" />
persistenceXmlLocation
- LocalContainerEntityManagerFactoryBean은 디폴트 위치인 META-INF에서 persistence.xml 파일을 찾음
- 일부 WAS에서는 META-INF/persistence.xml 파일을 자동으로 인식해서 서버가 관리하는 EntityManagerFactory와 충돌이 발생
- 따라서 스프링이 제공하는 컨테이너 관리 EntityManager를 적용하고 동시에 JPA 프로바이더를 제공하는 WAS에 배포할 경우 디폴트 위치에 persistence.xml을 넣는건 피해야 함
- persistenceXmlLocation의 프로퍼티에 파일 위치를 지정하여 변경
- 가장 간단한 방법은 파일의 이름을 spring-persistence.xml과 같이 변경하는 방법
<property name="persistenceXmlLocation" value="META-INF/spring-persistence.xml" />
jpaProperties, jpaPropertyMap
- EntityManagerFactory를 위한 프로퍼티를 지정할 때 사용
- jpaProperties는 <props>를 이용, jpaPropertyMap은 <map>을 이용해 정보를 입력
<!--persistence.xml--> <persistence-unit name="default"> ... <properties> <property name="eclipselink.waving" value="false" /> <properties> </persistence-unit>
- persistence.xml 파일 대신 스프링의 LocalContainerEntityManagerFactoryBean 빈에 정의
<!--LocalContainerEntityManagerFactoryBean--> <property name="jpaProperties"> <props> <prop key="eclipselink.waving">false</prop> </props> </property>
jpaVendorAdapter
- JPA는 비슷한 기능이지만 벤더별로 다른 설정 프로퍼티를 사용해야 하는 경우가 많음
- 구현 벤더별로 다르게 지정되는 프로퍼티나 설정을 JpaVendorAdapter를 이용하면 스프링이 정의한 표준 프로퍼티를 이용해 지정 가능
- JPA는 코드상에서 데이터 액세스 로직을 작성할 때 자바오브젝트와 전용 쿼리 언어, Criteria 등을 이용
- 이런 API와 오브젝트 쿼리 등을 DB가 이해할 수 있는 SQL 언어로 전환해서 처리
- ORM 계층의 언어와 API가 아닌 DB SQL을 출력하고 싶을때 아래와 같이 옵션 설정
<property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="showSql" value="true" /> </bean> </property>
- showSql이라는 프로퍼티는 true, false로 지정 가능
- 밴더 어댑터에 맞는 설정으로 변환 (EclipseLink: eclipselink.logging.level=FINE, 등)
- 스프링 3.1에선 EclipseLink. Hibernate, OpenJpa, TopLink 네가지 벤더를 위한 JpaVendorAdapter를 지원
JpaVendorAdapter
를 이용하면showSql
뿐 아니라 매핑 DDL을 자동생성해주는generatedDdl
과 DB 종류인database
, DB 플랫폼 정보인databasePlatform
등을 지정
- 이 외에도 각 벤더의 JPA 구현에 따라 달라지는 다양한 정보를
EntityManagerFactory
생성을 위헤 제공
loadtimeWeaver
- JPA는 POJO 클래스를 ORM의 엔티티로 사용
- POJO방식의 단점은 오브젝트가 만들어 진 후엔 컨테이너가 직접 관리할 수 없다는 점
- 엔티티 사이에 관계도 JPA 인터페이스가 아닌 직접 POJO 오브젝트끼리 연결 되있음
- JPA는 그래서 단순한 자바 코드로 만들어진 엔티티 클래스의 바이트코드를 직접 조작해서 확장된 기능을 추가하는 방식을 이용
- 엔티티 오브젝트 사이에 지연된 로딩이 가능
- 엔티티 값의 변화를 추적 가능
- 최적화와 그룹 페칭(fetching) 등의 고급 기능을 적용 가능
- 이미 컴파일된 클래스 바이트 코드를 조작해서 새로운 기능을 추가하는 것을 바이트코드 향상 기법이라고 함
- 클래스의 바이트 코드를 향상시키는 방법은 두가지
- 바이트코드를 빌드 중에 변경하는 것, JPA 벤더가 제공하는 바이트 코드 컴파일러가 필요하며 매번 빌드 작업중에 이 과정을 반드시 거쳐야 함
- 런타임 시에 클래스 바이트코드를 메모리에 로딩하면서 다이내믹하게 바이트코드를 변경해서 기능을 추가하는 방법
- 특별한 툴과 ANT 등을 이용한 번거로운 빌드 작업을 추가하지 않아도 되기 떄문에 애용되는 방법
- 런타임 시에 클래스를 로딩하면서 기능을 추가하는 것을 로드타임 위빙이라 하고 이런 기능을 가진 클래스를 로드타임 위버라고 부름
- 자바 5 이상에서는 JVM을 기동할 때 javaagent 옵션을 줘서 JVM이 로딩하는 모든 자바 클래스를 조작할 수 있는 기능을 넣었음
- JPA 구현 제품은 대부분 자바 에이전트를 이용해 로드타임 위버를 적용 가능
- 자바 에이전트는 간단해 보이지만 단점이 많음
- 엔티티 클래스는 몇십 개지만, JVM을 통해 로딩되는 모든 클래스를 일일이 다 확인
- 서버환경에서는 기동하는 JVM에 자바 에이전트를 설정해줘야하고, 운영정책과 관리 측면에서 부담을 줄 수 있어서 거부될 위험이 많음
- 스프링은 자바 에이전트 대신 특별한 클래스 로더를 이용해 로드타임 위빙 기능을 제공
- JPA 벤더에 종속되지 않는 방법을 통해 로드타임 위빙 기능 적용 가능 (5장 참고)
- org.springframework.instrument-3.0.7.RELEASE.jar를 사용
//자바 에이전트 -javaagent:eclipselink.jar //스프링이 제공하는 자바 에이전트 -javaagnet:lib/org/springframework.instrument-3.0.7.RELEASE.jar
- LocalContainerEntityManagerFactoryBean의 loadtimeWaver프로퍼티를 아래로 지정
<property name="loadTimeWeaber"> <bean class= "org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /> </property>
트랜잭션 매니저
- 컨테이너가 관리하는
EntityManager
방식에는 컨테이너가 제공하는 트랜잭션 매니저가 반드시 필요
- 스프링의 EntityManager를 사용하려면 적절한 트랜잭션 매니저 등록이 필요
- 스프링 JDBC는 트랜잭션 매니저가 없어도 동작, JDBC 자체가 자동 트랜잭션 모드를 갖고 있기 때문에 명시적으로 트랜잭션 관리를 안해도 됌
- 반면 JPA는 반드시 트랜잭션 안에서 동작하도록 설계
- LocalContainerEntityManagerFactoryBean을 통해 컨테이너 관리 EntityManger를 사용할 때는 트랜잭션 매니저를 다음과 같이 추가
<bean id="emf" class=
"org.springframework.orm.jpa.localContainerEntityManagerFactoryBean">
...
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
- JPA를 이용하는 DAO 코드는 스프링이 관리하는 트랜잭션 관리 기능을 이용 가능
- @Transactional이나 트랜잭션 AOP를 이용해서 트랜잭션 경계설정을 해주면 자동으로 JPA 트랜잭션을 시작하고 커밋하도록 만듬
JpaTransactionManager
를 사용하면DataSource
를 공유하는 JDBC DAO와 트랜잭션 공유 가능 (서비스 계층의 코드가 JPA DAO와 JDBC DAO를 하나의 트랜잭션 안에서 사용 가능)
- JTA 트랜잭션을 이용하는 경우라면 JtaTransactionManager를 사용
2.4.2 EntityManager와 JpaTemplate
- JDBC나 iBatis를 사용한 템플릿처럼 JPA도 템플릿 방식을 지원
- 템플릿을 통해 JPA 코드가 스프링 트랜잭션과 동기화 할 수 있도록 하고 예외를 변환하는 등의 기능을 지원 받음
- 스프링에선 JpaTemplate뿐 아니라 JPA API를 직접 사용해 DAO를 작성 가능
- JPA의 핵심 프로그래밍 인터페이스는 EntityManager
- EntityManager 오브젝트를 가져올 수 있으면 JPA의 모든 기능을 이용 가능
JpaTemplate
- jdbcTemplate, SqlMapClientTemplate와 동일하게 템플릿 방식으로 JPA 코드를 작성 가능
- 장점 : 템플릿을 이용하면 반복 작업을 줄여주고 예외 변환같은 편리한 기능을 제공
- 단점 : 데이터 액세스 기술이 직접 제공하는 API 대신 템플릿의 메소드와 콜백을 사용
- 스프링에선 JPA를 사용할 때 JpaTemplate은 자주 사용 안함
- JPA API가 익숙치 않고 스프링 템플릿 방식이 편리할 때 JpaTemplate를 사용 권장
public class MemberTemplateDao {
private JpaTemplate jpaTemplate;
@Autowired
public void init(EntityManager emf) {
jpaTemplate = new JpaTemplate(emf);
}
}
JpaDaoSupport
클래스를 상속해서 DAO를 만들면JpaTemplate
생성코드 생략 가능JpaTemplate
필요할 떄는getJpaTemplate()
를 이용
JpaTemplate
를 사용할 떄는 기본적으로JpaCallback
인터페이스의doInJpa()
에 필요한 작업을 입력
DoinJpa()
는 파라미터로EntityManager
를 전달, 이를 통해 모든 JPA 기능을 사용가능
List<Member> ms = templateDao.jpaTemplate.execute(new JpaCallback<List<Member>>() {
public List<Member> doInJpa(EntityManager entityManager) throws
PersistenceException {
return entityManager.createQuery("select m from Member m".getResultList();
}
});
- JpaTemplate은 콜백 오브젝트 없이도 간단한 메소드를 이용해 EntityManager가 제공하는 대부분의 기능을 사용 가능하게 해줌
Member m = new Member(1, "Spring", 8.9);
jpaTemplate.persist(m);
Member m2 = templateDao.jpaTemplate.find(Member.class, 1);
애플리케이션 관리 EntityManager와 @PersistenceUnit
- 애플리케이션 코드가 관리하는 EntityManager는 JavEE환경과 JavaSE 모두 사용 가능
- EntityManager는 EntityManagerFactory가 있다면 다음과 같이 직접 생성
EntityManager em = entityManagerFactory.createEntityManager();
- 컨테이너가 관리하지 않는 EntityManager이므로 트랜잭션은 다음과같이 사용
em.getTransaction().begin();
Member m = new Member(1, "Spring", 7.8);
em.persist(m);
Long count = em.createQuery("select count(m) from Member m", Long.class)
.getSingleResult();
em.getTransaction().commt();
@Autowired, @Resource
- EntityManagerFactory를 빈으로 등록하는 것은 LocalContainerEntityManagerFactoryBean을 이용하는 방법과 JNDI를 통해서 서버가 제공하는 EntityManagerFactory를 가져와 빈으로 사용하는 방법 두가지가 존재
- 어떤 방법이든 EntityManagerFactory는 빈으로 등록되므로 @Autowired, @Resource 또는 일반적인 스프링 DI방식으로 DAO 사용 가능
public class MemberDao {
@Autowired EntityManagerFactory emf;
public void addMember(Member member) {
EntityManager em = emf.createEntityManager();
...
}
}
- EntityManagerFactory는 EntityManager를 만들 수 있는 createEntityManager()를 제공
@PersistenceUnit
- EJB에서 JPA를 사용할 때와 비슷
- 스프링의 DI 방식 대신 JPA 표준 스팩에 나온 방식을 이용
- javax.persistence 패키지의 @PersistenceUnit 애노테이션을 사용
public class MemberDao {
@PersistenceUnit EntityManagerFacotry emf;
@Autowired
를 쓸때와 다른점은 스프링 의존도가 전혀 없는 순수한 JPA 코드라는 점
- JavaEE 컨테이너에서 EntityManagerFactory를 제공받아 사용하는 전형적인 JPA 코드
- @PersistenceUnit에 의해 주입되려면 애노테이션을 이용한 의존관계 설정이 가능한 컨테이너이거나, XML에 반드시 다음 설정이 필요
<context:annotation-config />
- 내부적으론
<context:annotation-config />
에 의해 자동등록되는PersistenceAnnotationBeanPostProcessor
후처리기가 @PersistenceUnit에 대한 DI 담당
- EntityManagerFactory를 직접 이용하는 방법은 실제로 자주 사용 안함
- EntityManagerFactory 인터페이스에서 제공하는 QueryBuilder, Metamodal, PersistenceUnitUtil을 가져오거나 캐시나 프로퍼티 정보를 참조할 필요가 있을때 사용
컨테이너 관리 EntityManager와 @PersistenceContext
- DAO가 컨테이너로부터 EntityManager를 직접 주입받으려면 JPA의 @PersistenceContext을 사용
- EntityManager는 스프링의 빈으로 등록하지 않음, 따라서 스프링 DI 방법으론 주입X
- 스프링에서는 JavaEE 컨테이너가 관리하는 EntityManager를 주입받는 방법을 스프링 애플리케이션의 코드에도 동일하게 사용 가능
- 표준 스펙을 따르는 프로그래밍 모델을 스프링에서도 동일하게 사용 가능해짐
- LocalContainerEntityManagerFactoryBean에 의해 등록된 EntityManagerFactory로부터 컨테이너가 관리하는 EntityManager를 직접 DOA에 주입받는 예시
public class MemberDao { @PersistenceContext EntityManager em; public void addMember(Member member) { em.persist(member); }
- EntityManager는 인스턴스 변수에 한 번 주입받아서 재사용 못함
- EntityManager는 그 자체로 멀티스레드에서 공유 할 수 없음
- 트랜잭션마다 하나씩만 만들어져서 사용되고 트랜잭션이 종료되면 함꼐 제거가 돼야 함
- 인스턴스 변수에서 한번 DI 받아놓고 여러 스레드에서 사용할 수 있는 이유
- @PersistenceContext로 주입받은 EntityManager는 실제가 아니라 현재 진행 중인 트랜잭션에 연결되는 퍼시스턴스 컨텍스트를 갖는 일종의 프록시
- 하나의 오브젝트를 공유하는 듯하지만 각 스레드가 자신의 컨텍스트에 따라서 만들어진 독립적인 오브젝트를 사용하도록 연결해주는 기능을 가진 프록시를 이용하는 것
- 컨테이너가 관리하는 EntityManager도 이와 비슷한 방식으로 동작
- DAO에서 마치 하나의 EntityManager를 독점적으로 사용하듯이 접근하지만 실제로는 트랜잭션마다 다른 EntityManager 오브젝트를 사용
EntityManager
가 존재하는 컨텍스트가 트랜잭션 범위이므로 type 앨리먼트는 아래와 같이 default 값이 적용@PersistenceContext(type=PersistenceContextType.TRANSACTION) EntityManager em;
- JPA 스펙에 따르면 트랜잭션 스코프의 퍼시스턴스 컨텍스트는 JTA를 통해 트랜잭션 관리
- 스프링은 이를
JpaTransactionManager
를 통해 관리하기 떄문에JavaEE
서버의 트랜잭션 매니저와 JTA가 없어도 JPA의 장점인@PersistenceContext
를 통한EntityManager
주입 가능
@PersistenceContext와 확장된 퍼시스턴스 컨텍스트
- @PersistenceCOntext를 이용해서 컨테이너가 관리하는 EntityManager를 주입
- 다만 type 앨리먼트의 값이 다름, type을
PersistenceContextType.EXTENDS
로 지정
- 트랜잭션 스코프 대신 확장된 스코프를 갖는 EntityManager가 만들어짐
- JPA에서 확장된 퍼시스턴스 컨텍스트는 상태유지 세션빈에 바인딩되는 것을 의미
- 상태유지 세션빈은 사용자별로 독립적이며 장기간 보존되는 오브젝트를 생성
- 세션빈에 바인딩되는 EntityManager 역시 사용자별로 독립적으로 장기간 보존
- 상태를 가진 세션빈이나 장기간 지속되는 스코프 빈에만 싱글톤 빈으로 사용 가능
- 하나 이상의 오브젝트로 만들어지기 때문에 각각 독립적으로 EntityManager를 가질 수 있기 때문에 스코프 프록시를 사용할 필요가 없음
public class MemberDao {
@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;
- 확장된 퍼시스턴스 컨텍스트는 싱글톤 빈에 적용하면 안되며, 상태를 가진 세션빈 또는 스프링 스코프 빈의 활용 방법을 잘 이해하고 이에 맞게 EntityManager 활용할때 추천
JPA 예외 반환
- JpaTemplate이 JPA API를 직접 사용하는 방법이 좀 더 나은 점은 JPA의 예외를 스프링의 데이터 액세스 예외 추상화 클래스 계층인 DataAccessException의 예외를 반환해준다는 점
- JPA의 API는 자동 예외 변환이 발생X, 런타임 예외를 발생시키기 떄문에 try/catch 블록이나 throws 선언이 필요 없음
- EntityManager와 같은 리소스 관리는 JPA 지원 컨테이너가 알아서 관리
JPA 예외 변환 AOP
- JPA API를 직접 이용하는 경우에도 JPA 예외를 스프링의 DataAccessException 전환 가능
- AOP를 이용해서 JPA API가 던지는 JPA 예외를 스프링의 예외로 전환하는 부가기능을 추가
- 이 방법을 이용하려면 다음 두가지 작업이 필요
@Repository
- 예외 변환이 필요한 DAO 클래스에 @Repository 애노테이션을 부여
- @Repositry는 @Component와 같은 자동인식을 위한 스테레오타입 애노테이션
- 빈 스캐너를 사용하지 않는 경우에도 @Repository를 DAO에 사용 가능
- @Repository가 붙은 DAO 클래스의 메소드는 AOP 예외 변환 기능이 부가될 빈으로 선정
PersistenceExceptionTranslationPostProcessor
- @Repository가 붙은 빈을 찾아 예외 변환 기능을 가진 AOP 어드바이스를 적용해주는 후처리기가 필요
- PersistenceExceptionTranslationPostProcessor를 빈으로 등록만 하면 사용 가능
<bean class=
"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
- SQL 에러 코드를 직접 해석해서 일관된 의미의 예외로 변환해주는 JdbcTemplate의 예외 변환과는 달리, JPA의 예외 자체가 분류하기 힘든 예외로 던져주기 떄문에 해석해서 변환
- JPA 스펙이 정의하는 예외는 제한적, 대부분의 DB 예외는 벤더가 정의한 예외나 시스템 예외 등으로 포장돼서 전달되고 스프링은 포장된 예외의 코드 수준까지 분석해 변환하는 기능X
- JPA 실행 중에 발생한 DB 예외등은 JDBC와 다른 방식으로 전달, 패러다임이 다르기 떄문에 발생하는 근본적인 한계
JDBC/iBatis
와JPA/하이버네이트
같은 ORM은 프로그래밍이 근본적으로 많은 차이 존재- POJO 기반의 투명한 영속성이 적용된 ROM의 엔티티 오브젝트를 사용하는 서비스 계층 코드와 항상 명시적으로 특정 SQL을 실행하는 JDBC/iBatis의 서비스 계층 코드는 미묘하지만 분명한 차이가 존재
- 예외 변환을 통해 완벽하게 독립적인 예외를 기대할 순 없지만 JPA의 예외를 스프링의 예외로 변경하는 건 가치가 있는 작업
@Repository
와PersistenceExceptionTanslationPostProcessor
를 이용한 예외 변환 AOP를 반드시 적용
'개발서적 > 토비 스프링 3.1-Vol.2' 카테고리의 다른 글
[토비의 스프링 - Vol.2] 2장 - 2.3 iBatis SqlMaps (0) | 2022.01.17 |
---|---|
[토비의 스프링 - Vol.2] 2장 - 2.2 JDBC (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 2장 - 2.1 공통개념 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.5.5 프로퍼티 소스 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.5.4 런타임 환경 추상화와 프로파일 (0) | 2022.01.17 |