在春季@Transactional方法期间处理异常
我试图弄清楚如何最好地处理持久性(以及潜在的其他)异常与Spring的.对于这篇文章,我将以用户注册的简单示例为例,这可能是由于重复的用户名而导致的。@Transactional
DataIntegrityViolationException
我尝试过以下事情,它们对我来说并不真正令人满意:
1. 幼稚的方法:抓住异常
val entity = UserEntity(...)
try {
repo.save(entity)
} catch (e: DataIntegrityViolationException) {
// not included: some checks for which constraint failed
throw DuplicateUsername(username) // to be handled by the controller
}
这在方法中不起作用,因为在提交事务之前不会发生持久性异常,这发生在spring事务包装器中的我的服务方法之外。@Transactional
2. 退出前冲洗EntityManager
显式调用 at end 的服务方法。这将强制写入数据库,从而触发异常。但是,它可能效率低下,因为我现在必须注意在请求期间不要无缘无故地多次刷新。我也最好永远不要忘记它,否则例外会消失在稀薄的空气中。flush
EntityManager
3. 创建两个服务类
将这些方法放在单独的弹簧豆中,并在主服务中尝试捕获它们。这很奇怪,因为我必须注意在A的位置执行代码的一部分,在B的位置执行另一部分。@Transactional
4. 控制器中的手柄DataIntegrityViolationException
只。。。不。控制器在处理数据库中的异常时没有业务(色相色调)。
5. 不要捕捉DataIntegrityViolationException
我在网络上看到过一些资源,特别是与Hibernate结合使用,建议捕获此异常是错误的,应该在保存之前检查条件(即通过手动查询检查用户名是否存在)。这在并发方案中不起作用,即使对于事务也是如此。是的,您将获得与交易的一致性,但是当“其他人先来”时,您仍然可以获得。因此,这不是一个可以接受的解决办法。DataIntegrityViolationException
7. 不要使用声明式事务管理
使用 Spring 的 TransactionTemplate
而不是 .这是唯一有点令人满意的解决方案。但是,使用起来比“只是扔在方法上”要“笨拙”得多,甚至Spring文档似乎也会促使您使用。@Transactional
@Transactional
@Transactional
我想就如何最好地处理这种情况提供一些建议。除了我上次提出的解决方案之外,还有更好的替代方案吗?