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

发布于 2024-11-03 11:00:18 字数 856 浏览 1 评论 0原文

我将 JPA 与 Spring 一起使用。如果我让 Spring 处理事务,那么假设 EntityManager 已正确注入到 DAO 中,我的服务层将如下所示:

MyService {

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

但是,如果我要手动执行事务,我必须确保传递该实例EntityManager 到事务中的每个 DAO 中。知道如何更好地重构吗?我觉得做 new MyDaoA(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();
       }
    }
}

I am using JPA with Spring. If I were to let Spring handle the transactions, then this is what my Service layer would look like assuming the EntityManager has been properly injected into the DAOs:

MyService {

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

However, if I were to do transactions manually, I have to make sure to pass that instance of EntityManager into each of the DAOs within a transaction. Any idea how can this be better refactored? I fee ugly doing new MyDaoA(em) or passing em into each DAO method like 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();
       }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深爱成瘾 2024-11-10 11:00:18

但是,如果我要做交易
手动,我必须确保通过
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代理

However, if I were to do transactions
manually, I have to make sure to pass
that instance of EntityManager into
each of the DAOs within a transaction.

This is where you are wrong. From the Spring Reference, JPA section:

The main problem with such a DAO is
that it always creates a new
EntityManager through the factory. You
can avoid this by requesting a
transactional EntityManager
(also
called "shared EntityManager" because
it is a shared, thread-safe proxy for
the actual transactional
EntityManager) to be injected instead
of the factory:

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(); 
    }
}

The @PersistenceContext annotation has
an optional attribute type, which
defaults to
PersistenceContextType.TRANSACTION.
This default is what you need to
receive a shared EntityManager proxy.

不疑不惑不回忆 2024-11-10 11:00:18

将其添加到您的 spring 配置中

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

,现在您可以在 dao 中使用 @Autowired EntityManager

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

因此使用 spring 的事务管理

作为

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

add this to your spring config

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

now you can @Autowired EntityManager inside your dao

for the transaction management, since you already using spring, and @Transactional annotation, i assume you already have one transaction manager declared in your spring.xml

so using spring's transaction management

as

transactionStatus = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
// do your work here 
platformTransactionManager.commit(transactionStatus );
岛歌少女 2024-11-10 11:00:18

我猜有点在黑暗中拍摄,但你知道你可以这样做吗:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

这通常消除了您希望/需要在具有声明性的系统中使用编程式事务的大多数情况交易。

Shot in the dark a bit I guess, but do you know you can do:

TransactionInterceptor.currentTransactionStatus().setRollbackOnly();

That usually eliminates the majority of cases where you would want/need to use programmatic transactions in a system that otherwise has declarative transactions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文