java - 在 Spring 中的 @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
}
这在方法中不起作用@Transactional
,因为在提交事务之前不会发生持久性异常,这发生在我在 spring 事务包装器中的服务方法之外。
EntityManager
2.退出前冲洗
flush
在EntityManager
我的服务方法结束时显式调用。这将强制写入数据库并因此触发异常。但是它可能效率低下,因为我现在必须注意不要在请求期间无缘无故地刷新多次。我也最好永远不要忘记它,否则例外会消失得无影无踪。
3.制作两个服务类
将这些@Transactional
方法放在一个单独的 spring bean 中,并在主服务中尝试捕获它们。这很奇怪,因为我必须注意将代码的一部分放在 A 位置,另一部分放在 B 位置。
4.DataIntegrityViolationException
控制器中的手柄
就是不行。控制器在处理来自数据库的异常时没有任何业务(hue hue hue)。
5.不要抓DataIntegrityViolationException
我在网上看到了一些资源,尤其是与 Hibernate 结合使用,这表明捕获此异常是错误的,应该在保存之前检查条件(即通过手动查询检查用户名是否存在)。这在并发场景中不起作用,即使使用事务也是如此。DataIntegrityViolationException
是的,您将获得与事务的一致性,但是当“其他人先来”时,您仍然会获得一致性。因此,这不是一个可接受的解决方案。
7. 不要使用声明式事务管理
使用 Spring 的TransactionTemplate
而不是@Transactional
. 这是唯一有点令人满意的解决方案。但是,使用它比“仅仅使用@Transactional
方法”要“笨拙”得多,甚至 Spring 文档似乎也促使您使用@Transactional
.
我想要一些关于如何最好地处理这种情况的建议。我上次提出的解决方案有更好的替代方案吗?
解决方案
我在我的项目中使用以下方法。
- 自定义注释。
public @interface InterceptExceptions
{
}
- 春季上下文中的 Bean 和方面。
<beans ...>
<bean id="exceptionInterceptor" class="com.example.ExceptionInterceptor"/>
<aop:config>
<aop:aspect ref="exceptionInterceptor">
<aop:pointcut id="exception" expression="@annotation(com.example.InterceptExceptions)"/>
<aop:around pointcut-ref="exception" method="catchExceptions"/>
</aop:aspect>
</aop:config>
</beans>
import org.aspectj.lang.ProceedingJoinPoint;
public class ExceptionInterceptor
{
public Object catchExceptions(ProceedingJoinPoint joinPoint)
{
try
{
return joinPoint.proceed();
}
catch (MyException e)
{
// ...
}
}
}
- 最后,使用。
@Service
@Transactional
public class SomeService
{
// ...
@InterceptExceptions
public SomeResponse doSomething(...)
{
// ...
}
}
推荐阅读
- javascript - 在javascript中的嵌套对象数组中查找百分比值
- c# - 只有第一个 if 语句触发
- unit-testing - 如何订阅角度服务单元测试中的错误案例
- laravel - 将 Laravel 安装克隆到 Homestead 时出错 - 是数据库问题还是证书问题?
- javascript - 只转义 HTML 而不是使用像 DOMPurify 这样的库来防止 XSS 是否安全?
- database - Is it possible to stop Oracle DB grants for specific user?
- c - 在 SystemV ABI 中返回一个结构
- python - 在为数据类中的字段初始化默认值时调用方法
- node.js - linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误
- ubuntu - 如何在 Ubuntu Vim 中启用剪贴板