EntityManager 와 영속 컨텍스트
이번 포스팅에서는 엔티티매니저와 영속컨텍스트에 대해서 알아보려한다. 그전에 엔티티와 엔티티매니저가 무엇인지 알아야 하는데 이에 대해서는 이전에 정리한 내용이 있으니 참고하길 바란다.
+ JPA
JPA를 이용하여 개발한 프로그램 코드는 보통 다음과 같은 패턴으로 개발된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | EntityManager emf = Persistence.createEntityManagerFactory("jpastart"); EntityManager em = emf.createManager(); EntityTransaction transaction = em.getTransaction(); try { transaction.begin(); Sight sight = em.find(Sight.class, 1); sight.setDetail(new SightDetail('오전9~오후5시', '연중무휴', '100여대 주차가능')); transaction.commit(); } catch(Exception e) { transaction.rollback(); throw e; } finally { em.close(); emf.close(); } | cs |
엔티티매니저를 생성한 이후 트랜잭션을 시작하고 엔티티매니저를 사용하여 엔티티(Sight)를 검색하고 명소정보(SightDetail)를 지정한 이후 트랜잭션을 커밋한다. 얼핏 일반적인 jdbc를 이용한 프로그래밍 패턴과 비슷하지만 JPA는 큰 차이점이 있다.
영속 컨텍스트
엔티티, 엔티티매니저와 영속 컨텍스트의 관계는 어느정도 이해가 됐을 것 같은데 간단히 정리하면 아래의 그림과 같다.
프로그램에서 엔티티매니저를 이용하여 데이터를 검색요청하면 영속 컨텍스트에 데이터가 없을 경우 DB에서 검색하여 영속 컨텍스트에 엔티티로 저장한다. 이후에 같은 식별자를 가지는 데이터를 요청할 경우에는 DB에서 검색하는 것이 아니라 영속 컨텍스트에서 검색한 결과를 반환한다.
전체적인 흐름은 위와 같고 먼저 엔티티매니저에 대해 자세히 알아보도록 하자.
EntityManager(엔티티매니저)
종류 |
설명 |
애플리케이션 관리 엔티티매니저 |
애플리케이션에서 직접 emf를 생성하고 관리 |
컨테이너관리 엔티티매니저 |
JBoss EAP, 웹로직, TomEE와 같은 JEE 컨테이너가 EMF를 생성하고 관리 |
전자는 앞선 코드에서 처럼 프로그램 코드에서 직접 EntityManager를 직접 생성하고 종료하는 방식을 말한다. 반면 컨테이너 관리 엔티티매니저는 프로그램 코드가 아닌 JEE 컨테이너에서 EntityManager의 라이프사이클(생성~종료)을 관리한다. 1
아래의 예제에서 보이다시피 EntityManager에 대한 생성과 종료에 대한 코드가 없다. JEE 컨테이너는 @Transactional 애노테이션이 적용된 메서드를 트랜잭션 범위에서 실행한다. 즉 메소드가 실행될때 트랜잭션이 시작(begin)되고 메서드가 종료될 때 트랜잭션이 완료(commit)되는 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | @PersistenceContext EntityManager em; @Transactional public void withdraw(String email) { User user = em.find(User.class, email); if(user == null) { throw new UserNotFoundException(); } em.remove(user); } | cs |
트랜잭션
1 2 3 4 5 6 7 8 9 10 11 12 | EntityManager em = emf.createEntityManager(); Transaction tx = em.createTransaction(); try { tx.begin(); //... tx.commit(); } catch(Exception e) { tx.rollback(); } finally { em.close(); } | cs |
다음은 JTA 트랜잭션 방식인데 JTA 트랜잭션을 사용하면 JPA에서 트랜잭션을 관리하지 않는다. 대신 EntityManager를 JTA 트랜잭션에 참여시켜 트랜잭션을 관리한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | UserTransaction utx = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction"); utx.begin(); // JTA 트랜잭션 시작 EntityManager em = emf.createEntityManager(); em.joinTransaction(); // JTA 트랜잭션에 참여 try { // ... utx.commit(); } catch(Exception e) { utx.rollback(); } finally { em.close() } | cs |
위의 코드에서 5라인의 joinTransaction()을 호출하지 않으면 엔티티의 변경이 있을 경우 실제 DB에 반영되지 않는다. 그 이유는 JPA는 트랜잭션 내에서의 변경만 DB에 반영하는데 JTA트랜잭션 방식을 사용하면 엔티티매니저는 트랜잭션에 관여하지 않고 엔티티매니저가 JTA 트랜잭션에 참여하지 않았으니 실제 DB에 반영되지 않는 것이다.
엔티티매니저의 영속 컨텍스트 전파
- Enterprise급 개발에 필요한 모든 기술을 담고 있는 기술 (트랜잭션, JSP, 서블릿 등..)을 사용할 수 있는 환경 [본문으로]