SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-003编写JPA-based repository( @PersistenceUnit、 @PersistenceContext、PersistenceAnnotationBeanPostProcessor)
一、注入EntityManagerFactory的方式
1 package com.habuma.spittr.persistence; 2 import java.util.List; 3 import javax.persistence.EntityManagerFactory; 4 import javax.persistence.PersistenceUnit; 5 import org.springframework.dao.DataAccessException; 6 import org.springframework.stereotype.Repository; 7 import org.springframework.transaction.annotation.Transactional; 8 import com.habuma.spittr.domain.Spitter; 9 import com.habuma.spittr.domain.Spittle; 10 @Repository 11 @Transactional 12 public class JpaSpitterRepository implements SpitterRepository { 13 @PersistenceUnit 14 private EntityManagerFactory emf; 15 public void addSpitter(Spitter spitter) { 16 emf.createEntityManager().persist(spitter); 17 } 18 public Spitter getSpitterById(long id) { 19 return emf.createEntityManager().find(Spitter.class, id); 20 } 21 public void saveSpitter(Spitter spitter) { 22 emf.createEntityManager().merge(spitter); 23 } 24 ... 25 }
这种方式有一个问题,Aside from presenting a troubling code-duplication situation, it also means a new EntityManager is created every time one ofthe repository methods is called. This complicates matters concerning transactions.
二、注入EntityManager的方式(其实并注入代理)
若用注入EntityManager的方式,也有一个问题,The problem is that an EntityManager isn’t thread-safe and generally shouldn’t be injected into a shared singleton bean like your repository. But that doesn’t mean you can’t ask for an EntityManager anyway.
1 package com.habuma.spittr.persistence; 2 import java.util.List; 3 import javax.persistence.EntityManager; 4 import javax.persistence.PersistenceContext; 5 import org.springframework.dao.DataAccessException; 6 import org.springframework.stereotype.Repository; 7 import org.springframework.transaction.annotation.Transactional; 8 import com.habuma.spittr.domain.Spitter; 9 import com.habuma.spittr.domain.Spittle; 10 @Repository 11 @Transactional 12 public class JpaSpitterRepository implements SpitterRepository { 13 @PersistenceContext 14 private EntityManager em; 15 public void addSpitter(Spitter spitter) { 16 em.persist(spitter); 17 } 18 public Spitter getSpitterById(long id) { 19 return em.find(Spitter.class, id); 20 } 21 public void saveSpitter(Spitter spitter) { 22 em.merge(spitter); 23 } 24 ... 25 }
关于线程的安全问题,The truth is that @PersistenceContext doesn’t inject an EntityManager —at least,not exactly. Instead of giving the repository a real EntityManager , it gives a proxy to a real EntityManager . That real EntityManager either is one associated with the current transaction or, if one doesn’t exist, creates a new one. Thus, you know that you’re
always working with an entity manager in a thread-safe way.
@PersistenceUnit and @PersistenceContext是JPA的标准,要让Spring明白这两个标签的注入方式,则要配置PersistenceAnnotationBeanPostProcessor,但若是使用 <context:annotation-config> or <context:component-scan> ,则默认是已经配置了的
1 @Bean 2 public PersistenceAnnotationBeanPostProcessor paPostProcessor() { 3 return new PersistenceAnnotationBeanPostProcessor(); 4 }
@Transactional indicates that the persistence methods in this repository are involved in a transactional context.