Spring @Transactional 合并和持久化问题

Posted

技术标签:

【中文标题】Spring @Transactional 合并和持久化问题【英文标题】:Spring @Transactional merge and persist question 【发布时间】:2010-12-07 17:25:01 【问题描述】:

Spring 新手,这里是 @***

我正在为分销商业务构建一个独立的库存和销售跟踪应用程序 (Apache Pivot/Spring/JPA/Hibernate/mysql)。

到目前为止,我认为一切都是 CRUD,所以我计划有一个包含 @Transactional 一切的基类。

然后我的保存通用方法出现问题。 Spring中EntityManager的persist和merge方法有区别吗?

我尝试运行并调用 save 以进行插入和更新,它工作正常(我认为 spring 每次我调用我的 save 方法时都会自动刷新实体 // 看到休眠查询被记录,对吗?)。

@Transactional
public abstract class GenericDAO 

    protected EntityManager em;

//  em getter+@PersistenceContext/setter

    public void save(T t) 
//        if (t.getId() == null) // create new
//        
//            em.persist(t);
//         else // update
//        
            em.merge(t);
//        
    

顺便说一句,有了这样的设置,我不会对性能造成太大影响,对吧?就像调用 salesDAO.findAll() 来生成报告一样(不需要是事务性的,对吧?)。

谢谢!!!

【问题讨论】:

【参考方案1】:

This SO question 很好地讨论了持久化与合并,并且接受的答案很好地解释了它。另一个答案还链接到关于此的一篇很好的博客文章。

根据this other post 的第一个回复,听起来可以调用merge 来保存和更新实体,但我不是这样做的。在我的 Spring/JPA 应用程序中,我只是让我的 DAO 扩展 JpaDaoSupport 并按以下方式使用 getJpaTemplate()。

/**
 * Save a new Album.
 */
public Album save(Album album) 
    getJpaTemplate().persist(album);
    return album;


/**
 * Update an existing Album.
 */
public Album update(Album album) 
    return getJpaTemplate().merge(album);

【讨论】:

我来宾这是最简单的方法。因此,如果我有 JpaDaoSupport,并且我从中获得了一个实体,那么任何更改都会自动提交吗?我想我会有两种保存方法的变体,一种是持久的,一种是调用刷新的。对此有何评论? 你的意思是自动提交没有保存或更新?如果是这样,我不这么认为,我总是只在新实体上调用 save 或在现有实体上更新以保持。我从来不需要调用 flush 方法,但是对于任何给定的请求,我的数据库访问都非常简单。 我现在不得不放弃尝试 Spring。只是好奇,Grails 对此有何改进?我不会在 Grails 中遇到类似的问题吧?【参考方案2】:

link 到 Kaleb 发布的另一个 SO 问题确实很好地涵盖了 persist() 与 merge() 的差异和陷阱。但是,我一直只是用一个 save() 方法实现我的 Dao 类,该方法只调用 merge() 来处理插入和更新,而且我从来没有遇到任何 persist() 与 merge() 陷阱。

就性能和事务方法而言: 在仅读取操作的方法上使用 @Transactional 不会真正影响性能,尽管我更喜欢在方法级别使用注释,这样我就可以轻松分辨哪些方法是更新的,哪些是读取的。您可以通过在@Transactional 注释上设置readOnly 属性来做到这一点。

如果您在方法中遵循命名约定(即任何读取方法始终以 getXXX 开头),您还可以在 Spring 配置文件中使用切入点语法来自动进行区分:

  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

请参阅Spring documentation on Transactions 了解更多信息。

另外,我通常将@Transactional 属性放在我的Dao 类的上一层,在服务层中。 Dao 类上的方法对于每个方法调用都是不同的数据库操作,而服务方法可以为一系列更新执行单个提交/回滚。

【讨论】:

感谢您的回答。我想我会坚持纯 JPA,(我对灵活性的需求不大)

以上是关于Spring @Transactional 合并和持久化问题的主要内容,如果未能解决你的问题,请参考以下文章

Spring @Transactional 和 Spring @Lock 注解有啥关系?

spring 和@transactional,这正常吗?

Spring @Transactional 和 @Async

Spring @Transactional 和 JDBC 自动提交

Spring @Transactional 使用

Spring Boot 和 Spring Data JPA @Transactional 不工作