@transactional(事务讲解)和springboot整合事务

好记性不如烂笔头=》      2022-04-28     551

关键词:

概述 事务在编程中分为两种:声明式事务处理和编程式事务处理

编程式事务处理:编码方式实现事务管理,常与模版类TransactionTemplate(推荐使用) 在业务代码中实现事务

可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。

 

声明式事务处理:

声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现,下面详细说明2种方法如何配置,已经相关注意点

1)方式一,配置文件如下

1)方式二(推荐),介绍如下

//获取连接 
21.Connection con = DriverManager.getConnection()
3//开启事务
42.con.setAutoCommit(true/false);
53.执行CRUD
6//提交事务/回滚事务 
74. con.commit() / con.rollback();
8//关闭连接
95. conn.close();

@Transactional 是声明式事务管理 编程中使用的注解

添加位置

接口实现类或接口实现方法上,而不是接口类中
访问权限:public 的方法才起作用

 

Spring本身并不提供事务,而是对JDBC事务通过AOP做了封装,隐藏了2和4的操作,简化了JDBC的应用。

spring对JDBC事务的封装,是通过AOP动态代理来实现的,在调用目标方法(也就是第3步)前后会通过代理类来执行事务的开启、提交或者回滚操作。

注意关键词“动态代理”,这意味着要生成一个代理类,那么我们就不能在一个类内直接调用事务方法,否则无法代理,而且该事务方法必须是public,如果定义成 protected、private 或者默认可见性,则无法调用!
忽略这两点,则很容易误用spring事务!


系统设计:将标签放置在需要进行事务管理的方法上,而不是不假思索的放置在接口实现类上( 接口中所有方法都需要进行事务管理,但其实并不需要,如只读的接口就不需要事务管理,但是 由于配置了@Transactional就需要AOP拦截及事务的处理,影响系统性能)

方法上注解属性会覆盖类注解上的相同属性,当接口与接口中方法上同时带有@Transactional注解时

错误使用:

接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效
接口中异常(运行时异常)被捕获而没有被抛出
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚
可通过 @Transactional rollbackFor进行配置
多线程下事务管理

因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean
在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制
一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,不会回滚线程中调用方法的事务

声明式事务管理实现方式:

  • 基于tx和aop名字空间的xml配置文件

基于@Transactional注解
@Transactional实质是使用了JDBC的事务来进行事务控制的
@Transactional基于Spring的动态代理的机制
@Transactional实现原理
1)事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入DataSource实例的某个与DataSourceTransactionManager相关的某处容器中。在接下来的整个事务中,客户代码都应该使用该connection连接数据库,执行所有数据库命令[不使用该connection连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚](物理连接connection逻辑上新建一个会话session;DataSource与TransactionManager配置相同的数据源)
2)事务结束时,回滚在第1步骤中得到的代理connection对象上执行的数据库命令,然后关闭该代理connection对象(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)

声明式事务的管理实现本质:
事务的两种开启方式
显示开启start transaction | begin,通过 commit | rollback 结束事务
关闭数据库中自动提交 autocommit set autocommit = 0;MySQL 默认开启自动提交;通过手动提交或执行回滚操作来结束事务
Spring 关闭数据库中自动提交:在方法执行前关闭自动提交,方法执行完毕后再开启自动提交

 

问题:

关闭自动提交后,若事务一直未完成,即未手动执行 commit 或 rollback 时如何处理已经执行过的SQL操作?

C3P0默认的策略是回滚任何未提交的事务
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等
JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互
------------------------------------------ --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 

spring事务特性

  • spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口
  • 事务的隔离级别:是指若干个并发
    的事务之间的隔离程度

    @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用

    @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)

    @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)

    @Transactional(isolation = Isolation.SERIALIZABLE):串行化

    事务传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为

    TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
    TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
    TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
    --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------

    @Transactional 属性配置

    说明:
    value :主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2.然后,用户可以根据这个参数来根据需要指定特定的txManager.
    value 适用场景:在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的
    REQUIRED_NEW和NESTED两种不同的传播机制的区别
    REQUIRED_NEW:内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;而外部的事务将不受内部事务的回滚状态影响
    ESTED的事务,基于单一的事务来管理,提供了多个保存点。这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。 由于这个设置基于JDBC的保存点,所以只能工作在JDBC的机制
    rollbackFor : 让受检查异常回滚;即让本来不应该回滚的进行回滚操作
    noRollbackFor :忽略非检查异常;即让本来应该回滚的不进行回滚操作

    嵌套事务
    带有事务的方法调用其他事务的方法,此时执行的情况取决配置的事务的传播属性

    PROPAGATION_REQUIRES_NEW :
    启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
    PROPAGATION_NESTED :
    如果外部事务 commit, 嵌套事务也会被 commit;如果外部事务 roll back, 嵌套事务也会被 roll back 。
    开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交
    关于Spring的事务Transactional,锁同步,并发线程
    --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 

    spring事务回滚规则
    指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常
    spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务
    默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
    用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    注意事项:
    @Transactional 使用位置 类上方、方法上方
    Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效
    当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

    方法的访问权限为 public
    @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常

    默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰
    例如一:同一个类中方法,A方法未使用此标签,B使用了,C未使用,A 调用 B , B 调用 C ;则外部调用A之后,B的事务是不会起作用的
    例如二:若是有上层(按照 Controller层、Service层、DAO层的顺序)由Action 调用 Service 直接调用,发生异常会发生回滚;若间接调用,Action 调用 Service 中 的A 方法,A无@Transactional 注解,B有,A调用B,B的注解无效
    --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 

    其他
    事务方法的嵌套调用会产生事务传播
    spring 的事务管理是线程安全的
    父类的声明的@Transactional会对子类的所有方法进行事务增强;子类覆盖重写父类方式可覆盖其@Transactional中的声明配置
    类名上方使用@Transactional,类中方法可通过属性配置覆盖类上的@Transactional配置;比如:类上配置全局是可读写,可在某个方法上改为只读
    源码阅读
    如果程序代码中由于历史原因遗留了接口内部方法调用的错误实现,可以用AspectJ 取代 Spring AOP 代理
    透彻的掌握 Spring 中@transactional 的使用
    Spring @Transactional工作原理详解

  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 
  • 参考资料
    spring的@Transactional注解详细用法
    Spring中@Transactional用法深度分析之一
    @Transactional事务几点注意
    spring @Transactional注解参数详解
    深入分析@Transactional的用法
    Spring @Transactional (一)
    Spring @Transactional工作原理
    @Transactional注解工作原理
    DBMS
    c3p0
    JNDI

  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 
    多线程事务管理
    描述

    因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean
    在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制
    解决

    如果方法中调用多线程
    方法主题的事务不会传递到线程中
    线程中可以单独调用Service接口,接口的实现方法使用@Transactional,保证线程内部的事务
    多线程实现的方法
    使用异步注解@Async的方法上再加上注解@Transactional,保证新线程调用的方法是有事务管理的
    原理

    Spring中事务信息存储在ThreadLocal变量中,变量是某个线程上进行的事务所特有的(这些变量对于其他线程中发生的事务来讲是不可见的,无关的)
    单线程的情况下,一个事务会在层级式调用的Spring组件之间传播
    在@Transactional注解的服务方法会产生一个新的线程的情况下,事务是不会从调用者线程传播到新建线程的
    参考资料

    Spring和线程:事务
    spring 多线程事务的问题
    --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 

    springBoot中使用事务

     

  • 1.在启动类上开启事务管理
  • @SpringBootApplication
    @MapperScan("net.xdclass.xdvideo.mapper")
    //开启事务管理
    @EnableTransactionManagement
    public class XdvideoApplication {

    public static void main(String[] args) {
    SpringApplication.run(XdvideoApplication.class, args);
    }
    }
  • 2在方法上或者类上开启事务
    @Transactional(propagation = Propagation.REQUIRED) 或者加上其他属性 在上面介绍的有
  • 参考博客:  https://blog.csdn.net/mingyundezuoan/article/details/79017659

spring声明式事务@transactional详解,事务隔离级别和传播行为(代码片段)

@Transactional注解支持9个属性的设置,这里只讲解其中使用较多的三个属性:readOnly、propagation、isolation。其中propagation属性用来枚举事务的传播行为,isolation用来设置事务隔离级别,readOnly进行读写事务控制。@Service@Transactional(readO... 查看详情

transactional什么情景下面会失效(代码片段)

Transactional失效的场景一:spring的事务管理讲解Transactional之前先来聊聊spring的事务。1:什么是事务?答:事务是一组操作,这组操作要么全部完成,要么全部失败。2:事务的特性?答:ACID四种原子性(Atomicity):事务是一个原... 查看详情

springboot事务的使用(编程式声明式)及@transactional工作原理失效处理(代码片段)

...重要的操作:它们对应的操作命令如下:--开启事务starttransaction;--业务执⾏--提交事务commit;--回滚事务rollback;Spring编程式事务(手动操作)Spring⼿动操作事务和 查看详情

springboot事务和事务传播机制(代码片段)

...事务的实现2.1Spring手动操作事务2.2Spring声明式事务3.@Transactional注解介绍3.1@Transactional作用范围3.2@Transactional参数说明3.3@Transactional出现异常注意事项3.4@Transactional工作原理4.事务隔离级别4.1事务特性4. 查看详情

springboot事务和事务传播机制(代码片段)

...事务的实现2.1Spring手动操作事务2.2Spring声明式事务3.@Transactional注解介绍3.1@Transactional作用范围3.2@Transactional参数说明3.3@Transactional出现异常注意事项3.4@Transactional工作原理4.事务隔离级别4.1事务特性4. 查看详情

springboot整合shiro涉及跨域和@cacheable缓存/@transactional事务注解失效问题

1.跨域(多出现在前后端分离项目中)  (1) 跨域介绍可参考:跨域(CORS)  (2)SpringBoot中解决跨域方式有:    A.使用@CrossOrigin注解;    B.实现Filter类,重写doFilter方法packagecom.ruhuanxingyun.config;importcn.hutool.core.util.StrUti... 查看详情

23.spring事务注解@transactional和异常捕获

一.事务注解限制条件1.不允许在private方法上面2.不能在非事务方法里面调用事务方法二.实现机制-异常捕获Describes transaction attributes on a method or class.This annotation type is generally&n 查看详情

spring@transactional事务注解的坑

1.在需要事务管理的地方加@Transactional注解。@Transactional注解可以被应用于接口定义和接口方法、类定义和类的public方法上。2. @Transactional注解只能应用到public可见度的方法上。如果你在protected、private或者package-visible的方法上... 查看详情

@Transactional 具有多个事务管理器和多个数据库

】@Transactional具有多个事务管理器和多个数据库【英文标题】:@TransactionalwithmultipleTransactionManagerandmultipledatabases【发布时间】:2019-07-0207:58:39【问题描述】:我为SpringBoot应用程序设置了以下内容:Database1-TransactionManagerDatabase1Data... 查看详情

jpa数据懒加载lazy配合事务@transactional使用

...话session还存在呢?今天讲解一种方法,借助Spring提供的@Transactional注解来实现方法内部的操作在同一次数据库连接中 查看详情

spring之注解事务@transactional

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:事务传播行为类型事务传播行为类型说明PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如... 查看详情

spring事物配置,声明式事务管理和基于@transactional注解的使用

...理两种方式。     编程式事务管理使用TransactionTemplate或者直接使用底层的P 查看详情

使用 Spring @Transactional 管理 Hibernate 事务

】使用Spring@Transactional管理Hibernate事务【英文标题】:ManageHibernatetransactionswithSpring@Transactional【发布时间】:2013-10-1820:57:04【问题描述】:我遇到了Spring3和Hibernate4的问题。我想使用@Transactional来管理休眠事务。我的JUnit测试适用... 查看详情

事务@transactional@transactional注解的rollbackfor属性(代码片段)

背景:代码是这样写的:@Service@TransactionalpublicclassLoginBizImplimplementsLoginBiz //....省略阿里巴巴规范扫描,它就提示attributerollbackforofannotationtranslationmustbeset问题说明嗯,查了一下,大意是这样子的1、spring或springboot框架下,使用@Tran... 查看详情

spring事务和事务传播机制(代码片段)

...栏:Spring系列文章目录为什么需要事务Spring声明事务Transactional参数说明propagationisolationtimeout事务回滚失效解决方案@Transactional工作原理Spring事务的传播机制为什么需要事务传播机制?传播机制的类型嵌套事务和加入事... 查看详情

spring事物配置,声明式事务管理和基于@transactional注解的使用

...理两种方式。     编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTempla 查看详情

Datanucleus:从@Transactional 迁移到非事务性

】Datanucleus:从@Transactional迁移到非事务性【英文标题】:Datanucleus:movingfrom@Transactionaltonon-transactional【发布时间】:2011-11-1307:45:23【问题描述】:我正在使用Datanucleus、JDO和Spring的声明式@Transactional管理与Aspect-J交织在一起。但是... 查看详情

带有 nolocks 和 TRANSACTION ISOLATION LEVEL READ COMMITTED 的 SQL 事务

】带有nolocks和TRANSACTIONISOLATIONLEVELREADCOMMITTED的SQL事务【英文标题】:SQLTransactionswithnolocksandTRANSACTIONISOLATIONLEVELREADCOMMITTED【发布时间】:2014-06-1720:19:36【问题描述】:我有一个这样的存储过程。CREATEPROCEDURE[dbo].[mysp]ASSETNOCOUNTONSETTRA 查看详情