热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springboot503_使用Spring的事务时,为什么我的事务失效了?

本文共xxxx字,将列举Spring事务失效的几种实际场景,帮助大家避免和发现此类问题,并保证事务的正常启用。前言Spring可谓是目前最

本文共xxxx字,将列举Spring事务失效的几种实际场景,帮助大家避免和发现此类问题,并保证事务的正常启用。

53fd532d8068ba5246e9cdbcc6e3aa4c.png

前言

Spring可谓是目前最流行的Java开发框架了,除了为开发者提供便利和强大的开发方式外,它也整合了数据库的事务功能,形成了一套事务管理的框架。

一般情况下,在SpringBoot强大的注解模式下,我们都是采用@Transaction的注解进行事务在方法层面的开启。

但很多情况下,会发现,咦,自己明明配置了注解,也启动了配置,为何事务不生效呢?

下面,我们就来列举下常见的几种事务失效场景。

事务失效场景总结
  • 数据库引擎本身不支持事务

当使用的数据库引擎不支持事务的时候,那么Spring即使开启了事务,也不会生效,要知道,Spring的事务管理实际上是对数据库事务的一次封装。

这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。

从 MySQL 5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是:MyISAM,所以这点要值得注意,底层引擎不支持事务再怎么搞都是白搭。

  • 数据源没有配置事务管理器

当程序引用的数据源,没有配置事务管理器时,便相当于没有事务管理,自然也不会生效

@Bean

public PlatformTransactionManager transactionManager(DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

  • 方法不是公用的public方法

Spring官方表示:@Transaction注解需要用在public方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启AspectJ的代理模式。

  • 该Bean没有被Spring创建

也就是说使用了@Transaction注解的方法,其所在的类没有被Spring创建为一个Bean,此时是不会被Spring所管理的,那么事务自然也就失效了。

  • 在事务传播中设置了不支持的模式

之前有一篇文章讲述了事务传播机制,其中有不支持事务的传播机制,比如说NOT_SUPPORTED。也就是说,当我们在@Transaction注解中,使用了不支持事务的传播机制时,此时事务是不会生效的。

比如:

@Service

public class TestServiceImpl implements TestService {

@Transactional(propagation = Propagation.NOT_SUPPORTED)

public void testTran(String arg) {

// doSomething

}

}

可见,当配置属性propagation为Propagation.NOT_SUPPORTED时,表示主动不以事务运行。

  • 异常捕获且不抛出

Spring的事务管理,实际上就是通过代理,在配置了@Transaction的方法前后拦截,在捕获到对应类型的异常时进行回滚。那么如果我们在方法里进行手动的try..catch,并且将捕获到的异常给吃了,那么Spring代理便无法得知方法调用的异常情况,就无法进行事务异常时的回滚操作。

比如:

@Service

public class TestServiceImpl implements TestService {

@Transactional

public void testTran(String arg) {

try{

// doSomething

} catch (Exception e){

// 捕获处理不抛出

}

}

  • 异常类型错误

Spring的事务异常回滚,有自己制定的异常类型,当满足了条件才会进行回滚,默认的异常类型为RuntimeException,那么此时如果我们抛出了非这个类型的异常时,同样是不会进行回滚的。

比如:

@Service

public class TestServiceImpl implements TestService {

@Transactional

public void testTran(String arg) {

try{

// doSomething

} catch (Exception e){

throw new Exception(....)

}

}

那么如何解决这个问题呢,我们可以通过配置@Transaction里的rollbackFor属性,指定为Exception.class来解决问题,但建议针对业务性异常,最好自己在程序里创建继承于RuntimeException的异常类,并显式抛出。

  • 自身调用问题

来看下下面这个代码:

@Service

public class TestServiceImpl implements TestService {

public void test(String arg){

this.testTran(arg);

}

@Transactional

public void testTran(String arg) {

try{

// doSomething

} catch (Exception e){

throw new RuntimeException(....)

}

}

当我们调用test()这个没有加事务的方法的时候,其调用的testTran()方法若是出现了异常,此时testTran()所启用的事务会回滚吗?

答案是不会的。

再看下面这个代码:

@Service

public class TestServiceImpl implements TestService {

@Transactional

public void test(String arg){

this.testTran(arg);

}

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void testTran(String arg) {

try{

// doSomething

} catch (Exception e){

throw new RuntimeException(....)

}

}

我们为test()方法开启事务,并且对其调用的方法,我们配置传播属性为——创建一个新事务。

此时这个新开的事务会生效吗?

答案也是不会的。

之所以不会,是因为它们发生了自身调用。这个问题可谓是许多人都会碰到的一种失效情况,大多数方法,我们会出现调用的情况,当调用了自身类的方法时,由于此时没有经过Spring的代理类,也就是内部调用了事务方法,这种情况将导致该调用方法的事务失效。

那么如何解决自身调用出现的事务失效问题呢?

  • 一种是在类中再注入自己,调用时通过注入的这个bean来进行方法调用,此时会由Spring的代理类进行方法调用,事务将生效,缺点是不优雅。
  • 一种是将调用方法写到另一个bean中,注入该bean再去调用,缺点无疑是将相同业务的代码拆分,导致复杂度增高。
  • 一种是通过AopContext.currentProxy()来获取当前代理,转换为当前类后进行方法调用。比如

((TestService)AopContext.currentProxy()).testTran(arg);

这种方式是官方为我们提出的解决方案,也建议使用这种方案,注意,使用AopContext.currentProxy()是需要将expose-proxy设置为true才能生效的。

Tip

以上列举出来了8种常见的事务失效场景和部分解决方案,其中最常见的便是“异常不抛出”、“异常类型不正确”以及“自身调用”这三个问题。



推荐阅读
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 本文深入解析了WCF Binding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。 ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
  • 在JavaWeb开发中,文件上传是一个常见的需求。无论是通过表单还是其他方式上传文件,都必须使用POST请求。前端部分通常采用HTML表单来实现文件选择和提交功能。后端则利用Apache Commons FileUpload库来处理上传的文件,该库提供了强大的文件解析和存储能力,能够高效地处理各种文件类型。此外,为了提高系统的安全性和稳定性,还需要对上传文件的大小、格式等进行严格的校验和限制。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 如何在方法上应用@ConfigurationProperties注解进行属性绑定 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 在Linux系统中避免安装MySQL的简易指南
    在Linux系统中避免安装MySQL的简易指南 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • 在编译 PHP7 的 PDO MySQL 扩展时,可能会遇到 `[mysql_driver.lo]` 错误 1。该问题通常出现在 `pdo_mysql_fetch_error_func` 函数中。本文详细介绍了导致这一错误的常见原因,包括依赖库版本不匹配、编译选项设置不当等,并提供了具体的解决步骤和调试方法,帮助开发者快速定位并解决问题。 ... [详细]
  • 本文详细介绍了在Linux系统上编译安装MySQL 5.5源码的步骤。首先,通过Yum安装必要的依赖软件包,如GCC、GCC-C++等,确保编译环境的完备。接着,下载并解压MySQL 5.5的源码包,配置编译选项,进行编译和安装。最后,完成安装后,进行基本的配置和启动测试,确保MySQL服务正常运行。 ... [详细]
  • Squaretest:自动生成功能测试代码的高效插件
    本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
author-avatar
seoer
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有