使用Spring的JPA手动事务服务和DAO层

时间:2011-04-28 00:27:27

标签: java hibernate spring jpa transactions

我在Spring中使用JPA。如果我让Spring处理事务,那么假设EntityManager已正确注入到DAO中,这就是我的服务层的样子:

MyService {

   @Transactional
   public void myMethod() {
       myDaoA.doSomething();
       myDaoB.doSomething();
    }
}

但是,如果我要手动执行事务,我必须确保将EntityManager的实例传递到事务中的每个DAO中。任何想法如何更好地重构?我很难做新的MyDaoA(em)或将em传递给每个DAO方法,如doSomething(em)。

MyService {

   private EntityManagerFactory emf;

   public void myMethod() {
       EntityManager em = emf.createEntityManager();
       EntityTransaction tx = em.getTransaction();
       MyDaoA myDaoA = new MyDaoA(em);
       MyDaoB myDaoB = new MyDaoB(em);
       try {
           tx.begin();
           myDaoA.doSomething();
           myDaoB.doSomething();
           tx.commit();
       } catch(Exception e) {
           tx.rollback();
       }
    }
}

3 个答案:

答案 0 :(得分:3)

  

但是,如果我要做交易   手动,我必须确保通过   那个EntityManager实例进入   交易中的每个DAO。

这是你错的地方。从Spring Reference,JPA section

  

这样一个DAO的主要问题是   它总是创造一个新的   EntityManager通过工厂。 您   通过请求a可以避免这种情况   事务性EntityManager (也是   称为“共享EntityManager”,因为   它是一个共享的,线程安全的代理   实际的交易   EntityManager)代替注入   工厂:

public class ProductDaoImpl implements ProductDao {

    @PersistenceContext
    private EntityManager em;

    public Collection loadProductsByCategory(String category) {
       Query query = em.createQuery(
                        "from Product as p where p.category = :category");
       query.setParameter("category", category);
       return query.getResultList(); 
    }
}
  

@PersistenceContext注释有   一个可选的属性类型,它   默认为   PersistenceContextType.TRANSACTION。   您需要此默认值   接收共享的EntityManager代理

答案 1 :(得分:1)

将此添加到您的弹簧配置

<bean p:entityManagerFactory-ref="emf" class='org.springframework.orm.jpa.support.SharedEntityManagerBean' />

现在你可以在你的dao中使用@Autowired EntityManager

对于事务管理,因为你已经使用了spring和@Transactional注释,我假设你已经在spring.xml中声明了一个事务管理器

所以使用spring的事务管理

as

transactionStatus = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
// do your work here 
platformTransactionManager.commit(transactionStatus );

答案 2 :(得分:0)

我想在黑暗中拍摄,但你知道你可以做到:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

这通常会消除您希望/需要在系统中使用程序化事务的大多数情况,否则这些事务具有声明性事务。