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.

原文地址:https://www.cnblogs.com/shamgod/p/5344763.html