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

     2023-02-26     61

关键词:

【中文标题】在 Spring 中的 @Transactional 方法期间处理异常【英文标题】:Handling exceptions during a @Transactional method in Spring 【发布时间】:2018-10-13 12:11:48 【问题描述】:

我试图找出如何结合 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 事务包装器中的服务方法之外。

2。退出前刷新EntityManager

在我的服务方法结束时在EntityManager 上显式调用flush。这将强制写入数据库并因此触发异常。但是它可能效率低下,因为我现在必须注意不要在请求期间无缘无故地刷新多次。我也最好永远不要忘记它,否则例外会消失得无影无踪。

3。创建两个服务类

@Transactional 方法放在一个单独的spring bean 中,并在主服务中围绕它们进行try-catch。这很奇怪,因为我必须注意将代码的一部分放在 A 位置,另一部分放在 B 位置。

4。在控制器中处理DataIntegrityViolationException

只是……不。控制器在处理来自数据库的异常时没有任何业务(hue hue hue)。

5。不要抓DataIntegrityViolationException

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

7。不要使用声明式事务管理

使用 Spring 的 TransactionTemplate 而不是 @Transactional。这是唯一有点令人满意的解决方案。然而,使用它比“只是在方法上抛出 @Transactional”要“笨拙”得多,甚至 Spring 文档似乎也在推动你使用 @Transactional

我想要一些关于如何最好地处理这种情况的建议。我上次提出的解决方案有更好的替代方案吗?

【问题讨论】:

为什么不作为 (3) 的变体,在同一个服务中有两种方法?一个是@Transactional,另一个是DataIntegrityViolationException 遇到同样的问题,我将使用 (3) 的这种变体,听起来是最好的方法。不要忘记将第二种方法也公开,因为它应该能够被“分割”(可能取决于您使用的 aop 框架)。 您好,您是否尝试过使用@ControlerAdvice?如果没有,也许看看here。 基本上就是第 4 点。根据 MVC,控制器层不应该处理来自数据库的异常。 【参考方案1】:

我在我的项目中使用以下方法。

    自定义注释。
public @interface InterceptExceptions


    Spring 上下文中的 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(...)
  
    // ...
  

【讨论】:

【参考方案2】:

您可以使用带有@ControllerAdvice 或@RestControllerAdvice 注解的类来处理异常

当控制器抛出异常时,您可以在此类中捕获它并将响应状态更改为合适的状态或添加异常的额外信息

此方法可帮助您保持干净的代码

你有很多例子:

https://www.javainuse.com/spring/boot-exception-handling

https://dzone.com/articles/best-practice-for-exception-handling-in-spring-boo

【讨论】:

【参考方案3】:

投票给(3),喜欢:

@Service
public class UserExtService extend UserService


@Service
public class UserService 
    @Autowired
    UserExtService userExtService;

    public int saveUser(User user) 
        try 
            return userExtService.save(user);
         catch (DataIntegrityViolationException e) 
          throw DuplicateUsername(username);// GlobalExceptionHandler to response
        
        return 0;
    

    @Transactional(rollbackFor = Exception.class)
    public int save(User user) 
        //...
        return 0;
    

【讨论】:

web.xml中的contextconfiglocation在spring中的作用

在web.xml中通过contextConfigLocation配置spring,contextConfigLocation参数定义了要装入的Spring配置文件。如果想装入多个配置文件,可以在 <param-value>标记中用逗号作分隔符或通配符。 在web.xml里配置Listenerweb.xml代码如下: ... 查看详情

spring在web.xml中的配置

在实际项目中spring的配置文件applicationcontext.xml是通过spring提供的加载机制,自动加载的容器中去,在web项目中,配置文件加载到web容器中进行解析,目前,spring提供了两种加载器,以供web容器的加载:一种是ContextLoaderListener,... 查看详情

@Autowired 在 Spring 中的类上

】@Autowired在Spring中的类上【英文标题】:@AutowiredonclassesinSpring【发布时间】:2020-05-2213:00:47【问题描述】:我有一个小问题。如果该类使用@Component、@Service、@Controller或@Repository进行注释,并且我想注入其依赖项,是否需要@Autowi... 查看详情

如何在 Spring Boot 中禁用 Spring Security 中的 CORS?

】如何在SpringBoot中禁用SpringSecurity中的CORS?【英文标题】:HowtodisableCORSinSpringSecuritywithinSpringBoot?【发布时间】:2021-06-2607:02:33【问题描述】:我想使用SpringSecurity从SpringBoot(2.3.3.RELEASE)中完全删除CORS。HttpSecurity对象有WebSecurityConf... 查看详情

spring在web.xml中的配置

Spring在web.xml中进行配置1.1加载Spring配置文件我们首先指定我们需要加载的Spring配置文件,在tomcat容器启动后,会寻找项目中的web.xml文件,加载其中的信息,并创建一个ServletContext上下文对象,以后再web应用中可以获得其中的值... 查看详情

在spring mvc中选择spring hibernate中的查询

】在springmvc中选择springhibernate中的查询【英文标题】:Selectqueryinspringhibernateinspringmvc【发布时间】:2014-07-1109:36:27【问题描述】:嗨,我正在编写一个springmvc,使用mysql数据库、hibernate注释和jsp的员工应用程序。该数据库包含一... 查看详情

Spring中的@SendToUser是不是仅在集成了Spring Security时才有效?

】Spring中的@SendToUser是不是仅在集成了SpringSecurity时才有效?【英文标题】:Does@SendToUserinSpringonlyworkswhenSpringSecurityisintegrated?Spring中的@SendToUser是否仅在集成了SpringSecurity时才有效?【发布时间】:2018-10-2311:51:37【问题描述】:我... 查看详情

web.xml中的contextconfiglocation在spring中的作用(代码片段)

一、spring中如何使用多个xml配置文件  1、在web.xml中定义contextConfigLocation参数,Spring会使用这个参数去加载所有逗号分隔的xml文件,如果没有这个参数,spring会默认加载WEB-INF/applicationContext.xml文件(若没有,要新建一个)。 ... 查看详情

在 Spring 中忽略 WebSecurity 配置中的路径

】在Spring中忽略WebSecurity配置中的路径【英文标题】:IgnoringpathinWebSecurityconfiginSpring【发布时间】:2018-04-0116:01:04【问题描述】:我有配置@Overridepublicvoidconfigure(WebSecurityweb)throwsExceptionweb.ignoring().antMatchers("/base/**");我想包含所有... 查看详情

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

】在Spring中的@Transactional方法期间处理异常【英文标题】:Handlingexceptionsduringa@TransactionalmethodinSpring【发布时间】:2018-10-1312:11:48【问题描述】:我试图找出如何结合Spring的@Transactional最好地处理持久性(以及可能的其他)异常。... 查看详情

Spring Annotation在不同层中的适用[重复]

】SpringAnnotation在不同层中的适用[重复]【英文标题】:ApplicableofSpringAnnotationindifferentlayers[duplicate]【发布时间】:2014-06-2615:10:48【问题描述】:由于Spring具有注释@Component来表示任何Spring管理组件。然后我们再次在MVC控制器bean中... 查看详情

spring中的aop

Spring的传统AOPAOP:不是由Spring定义.AOP联盟的组织定义.Spring中的通知:(增强代码)前置通知org.springframework.aop.MethodBeforeAdvice*在目标方法执行前实施增强后置通知org.springframework.aop.AfterReturningAdvice*在目标方法执行后实施增强环绕通知or... 查看详情

springboot中在普通类里面加载spring容器中的类

...言在我们的工作中,经常会遇到需要在普通类中使用放在Spring容器中的类的情况。最常见的情况大概就是有一个类他的属性的是通过spring的配置文件读取的。这样这个类必然要交给Spring容器进行管理。这个时候如果我们在普通类... 查看详情

详解设计模式在spring中的应用

...在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的思想理念,才能在工作学习中运用到“无形”。Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,... 查看详情

如何在 Spring 中的每次测试之前重新创建数据库?

】如何在Spring中的每次测试之前重新创建数据库?【英文标题】:Howtore-createdatabasebeforeeachtestinSpring?【发布时间】:2016-04-0914:24:43【问题描述】:我的Spring-Boot-Mvc-Web应用程序在application.properties文件中有以下数据库配置:spring.dat... 查看详情

使用 spring 框架将统计数据保存在文件中的最佳方法是啥?

】使用spring框架将统计数据保存在文件中的最佳方法是啥?【英文标题】:Whatisthebestapproachforsavingstatisticaldataonafileusingspringframework?使用spring框架将统计数据保存在文件中的最佳方法是什么?【发布时间】:2019-02-0102:46:04【问题... 查看详情

使用 Spring MVC 在 tomcat 中的 PATCH 方法

】使用SpringMVC在tomcat中的PATCH方法【英文标题】:PATCHmethodintomcatwithSpringMVC【发布时间】:2013-12-2016:15:36【问题描述】:我使用的是spring3.2.4,并且我读到SpringMVC3.2.X明确支持PATCHHTTP方法:https://jira.springsource.org/browse/SPR-7985http://doc... 查看详情

spring中的事务管理

在springboot中,使用事务非常的简单,因为springboot已经帮我们配置好了,只需要加上注解@Transactional即可在spring中我们需要做一些配置:主要有三点:@Transactional:在相应的方法上加上这个注解@EnableTransactionManagement:在配置类中... 查看详情