簡體   English   中英

JPA 和 Spring 的手動事務服務和 DAO 層

[英]Manual Transactional Service and DAO layer for JPA with Spring

我正在使用 JPA 和 Spring。 如果我讓 Spring 處理事務,那么假設 EntityManager 已正確注入 DAO,這就是我的服務層的樣子:

MyService {

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

但是,如果我要手動執行事務,我必須確保將該 EntityManager 的實例傳遞給事務中的每個 DAO。 知道如何更好地重構嗎? 我覺得做 new 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();
       }
    }
}

但是,如果我要手動執行事務,我必須確保將該 EntityManager 的實例傳遞給事務中的每個 DAO。

這是你錯的地方。 來自 Spring 參考, JPA 部分

這種 DAO 的主要問題是它總是通過工廠創建一個新的 EntityManager。 您可以通過請求注入事務性 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 代理所需要的。

將此添加到您的 spring 配置中

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

現在您可以在您的 dao 中使用 @Autowired EntityManager

對於事務管理,由於您已經使用 spring 和 @Transactional 注釋,我假設您已經在 spring.Z0F635D0E0F3874FFF8B581C132E6C7A 中聲明了一個事務管理器

所以使用spring的事務管理

作為

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

我猜有點在黑暗中拍攝,但你知道你可以做到:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

這通常會消除您希望/需要在具有聲明性事務的系統中使用編程事務的大多數情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM