有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在Spring的@Transactional方法期间处理异常

我试图找出如何结合Spring的@Transactional来最好地处理持久性(以及潜在的其他)异常。 在这篇文章中,我将以一个简单的用户注册为例,它可能会由于重复的用户名而导致DataIntegrityViolationException

我试过以下几件事,但都不太满意:

一,。天真的方法:抓住例外

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
}

这在@Transactional方法中不起作用,因为在提交事务之前不会发生持久性异常,这在spring事务包装器中我的服务方法之外发生

二,。退出前刷新EntityManager

在我的服务方法末尾的EntityManager上显式调用flush。这将强制写入数据库,从而触发异常。然而,这可能是低效的,因为我现在必须注意,在一个请求过程中,不要无缘无故地多次刷新。我也最好永远不要忘记它,否则例外会消失在空气中

三,。上两堂服务课

@Transactional方法放在一个单独的Springbean中,并在主服务中尝试捕获它们。这很奇怪,因为我必须注意将代码的一部分放在A位置,另一部分放在B位置

四,。在控制器中处理DataIntegrityViolationException

只是。。。不可以。控制器没有处理数据库异常的业务(色调)

五,。不要抓住DataIntegrityViolationException

我在网上看到了一些资源,尤其是与Hibernate结合使用的资源,它们表明捕获此异常是错误的,应该在保存前检查条件(即通过手动查询检查用户名是否存在)。这在并发场景中不起作用,即使在事务中也是如此。是的,您将获得与事务的一致性,但当“其他人先到”时,您仍将获得DataIntegrityViolationException。因此,这不是一个可接受的解决方案

七,。不要使用声明性事务管理

使用Spring的^{}而不是@Transactional。这是唯一稍微令人满意的解决方案。然而,它比“仅仅在方法上抛出@Transactional”要“笨拙”得多,甚至Spring文档似乎也在推动您使用@Transactional

我想要一些关于如何最好地处理这种情况的建议。除了我上次提出的解决方案,还有更好的选择吗


共 (0) 个答案