开始交易仅用于保存
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
,去看看!以上是关于开始交易仅用于保存的主要内容,如果未能解决你的问题,请参考以下文章
仅授权信用卡交易是不是应该与数据库中的授权捕获交易分开存储?
Authorized.net - 可以 createTransactionRequest 用于授权、捕获和取消现有支付配置文件 ID 的交易