开始交易仅用于保存

Posted

技术标签:

【中文标题】开始交易仅用于保存【英文标题】:Start a transaction for saving only 【发布时间】:2021-06-06 08:30:24 【问题描述】:

我想知道在以下情况下推荐的操作方式是什么:

假设我有一个 ReportService 负责生成报告、上传报告、发送电子邮件并将其保存到数据库中。 在数据库中保存时,它会更新很多实体,我想回滚整个内容以防出现故障。

所以应该是这样的:

@Service
public class ReportService 

    public void generateReport() 

        var entities = entityRepository.findEntities();

        var file = getReportData(entities);

        var url = uploadFile(file);
        
        sendEmail(url);

        // If something goes wrong while save on entity, roll back everything
        for (var e : entities) 
           entityRepository.save(e);
        
    

所以我知道我有以下选择:

使用 @Transactional 注释该方法:我认为这不是一个好主意,因为我们会将 HTTP 请求和工作负载与数据库事务混合在一起 创建一个全新的服务,例如ReportSavingService,并使用一种方法来仅保存这些实体:我认为这可行,但对我来说,处理与我已经拥有的相同业务逻辑的特定服务似乎很奇怪服务,只是为了保存它......

我想知道这些是否是我们处理 Spring Data 的解决方案,或者是否有一种简单的方法可以执行以下操作:

        // ...
        sendEmail(url);

        // If something goes wrong while save on entity, roll back everything
        database.beginTransaction();
        for (var e : entities) 
           entityRepository.save(e);
        
        database.commit();

我知道我们的这种控制有点下降,直接使用EntityManager,但是我不能将它与 Spring Data 的存储库方法混合...我可以吗?

【问题讨论】:

好吧,你可以注入TransactionTemplate并使用transactionTemplate.execute(...),但我建议重新考虑设计 - 请注意,当你首先运行不可逆操作时(发送电子邮件) ,总是存在执行永远不会到达持久性代码的风险。更好的方法是生成报告,将其保存到数据存储中,然后仅在事务成功后发送电子邮件(或者,更好的是,有一个单独的工作来通过电子邮件发送待处理的报告) 谢谢@crizzis,是的,我同意你的观点。这实际上不是一个真实的案例,只是一个例子:) 看看TransactionTemplate,不知道:D 【参考方案1】:

您正在寻找的是TransactionTemplate

@Autowired
TransactionTemplate tx;

// ...

    tx.execute(__ -> 
        for (var e : entities) 
           entityRepository.save(e);
        
    

我确实同意@crizzis 的评论,即设计似乎有些错误,但我认为这与问题无关。

【讨论】:

谢谢@Jens,没听说过TransactionTemplate,去看看!

以上是关于开始交易仅用于保存的主要内容,如果未能解决你的问题,请参考以下文章

自定义 Paypal 表单仅在完成交易后收集一些数据

SQL Server日志文件总结及日志满的处理

如何从多个授权交易中仅捕获一笔交易?

仅授权信用卡交易是不是应该与数据库中的授权捕获交易分开存储?

Authorized.net - 可以 createTransactionRequest 用于授权、捕获和取消现有支付配置文件 ID 的交易

用于分配付款的 Oracle SQL 查询