Spring-TX 事务

目录

一、事务的种类

二、Spring事务管理器

三、事务注解使用

四、事务注解属性


一、事务的种类

1.编程式事务

所谓编程式事务就是用代码手写事务,包含了事务的开始,具体事务,事务的提交和事务的回滚。在这期间就会产生一些冗余问题,比如事务的开始,事务的提交,事务的回滚。都是一些重复的代码,如果在事务很多的情况下,代码量会比较庞大,并且十分臃肿。

传统的编程式事务

Connection conn = ...;try {// 开启事务:关闭事务的自动提交conn.setAutoCommit(false);// 核心操作// 业务代码// 提交事务conn.commit();}catch(Exception e){// 回滚事务conn.rollBack();}finally{// 释放数据库连接conn.close();}

2.声明式事务

声明式事务是指使用注解或 XML 配置的方式来控制事务的提交和回滚。

开发者只需要添加配置即可, 具体事务的实现由第三方框架实现,避免我们直接进行事务操作!

优点:

使用声明式事务可以将事务的控制和业务逻辑分离开来,提高代码的可读性和可维护性。

区别:

  • 编程式事务需要手动编写代码来管理事务
  • 而声明式事务可以通过配置文件或注解来控制事务。

二、Spring事务管理器

2.1事务管理器介绍

使用SpringTx时候由于持久层框架的不同(如JDBC、JDBCTemplate、Mybatis等)使得Spring的事务管理接口有多个对应的实现类分别如下

  • spring-tx: 包含声明式事务实现的基本规范(事务管理器规范接口和事务增强等等)
  • spring-jdbc: 包含DataSource方式事务管理器实现类DataSourceTransactionManager
  • spring-orm: 包含其他持久层框架的事务管理器实现类例如:Hibernate/Jpa等

由于一般使用MyBatis,JDBC,JDBCTemplate都是使用DataSourceTransactionManager类。DataSourceTransactionManager的常用方法如下

方法名描述
doBegin()开启一个新的事务。
doSuspend()用于挂起当前事务上下文,并且暂停现有的事务。
doResume()恢复挂起的事务上下文,并继续已有的事务。
doCommit()提交当前事务。
doRollback()回滚当前事务。

 2.2事务管理器配置

需要先导入对应的依赖

<!-- 声明式事务依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.0.6</version></dependency>

在配置类中的具体配置

@Configuration
@ComponentScan("com.alphamilk")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
public class JavaConfig {@Value("${alphamilk.url}")private String url;@Value("${alphamilk.driver}")private String driver;@Value("${alphamilk.username}")private String username;@Value("${alphamilk.password}")private String password;@Bean//druid连接池public DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Bean//JDBCTemplatepublic JdbcTemplate jdbcTemplate( ){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource());return jdbcTemplate;}
//    设置TransactionManger事务管理接口@Beanpublic TransactionManager transactionManager(DataSource dataSource){
//        创建DataSourceTransaction对象DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
//        配置对应的数据源dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}
}

三、事务注解使用

使用的注解

注解描述
@EnableTransactionManagement启用事务管理。需要在配置类上添加该注解。
@Transactional标记需要事务管理的方法或类。可以在方法级别或类级别使用

使用的范围:类或是方法

当作用在方法上时候,其对应的仅仅是对某一个具体的事务声明。

案例代码:

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;@Transactionalpublic void changeInfo(){studentDao.updateAgeById(20,1);
//        设置异常,如果发生异常,则事务会自动回滚,即上面代码虽然执行,但是不会提交int i = 1/0;System.out.println("-----------");studentDao.updateNameById("test2",1);}
}

当作用在类上的时候,对类上所有的方法进行事务声明

案例代码:

@Service
@Transactional
public class StudentService {@Autowiredprivate StudentDao studentDao;public void changeInfo(){studentDao.updateAgeById(20,1);System.out.println("-----------");studentDao.updateNameById("test2",1);}
}

注意:在使用事务注解的时候,配置种记得需要设置开启事务声明的注解,并且注意@Transactional注解同时作用于类和方法上时候,作用在类上的注解会将类上的注解覆盖。即不享受类上事务声明的效果

@Configuration
@ComponentScan("com.alphamilk")
@PropertySource("classpath:jdbc.properties")
//开启事务声明注解
@EnableTransactionManagement

四、事务注解属性

事务注解中有多种属性,分别是只读模式,超出时间,,,。并且每一个属性都有其相应的异常

1.只读模式/设置

属性名称:readOnly (默认为false)

属性解释

当处于readOnly开启状态的时候,只能进行读取信息的操作,无法执行修改的操作,这么做可以提高事务的效率。

案例代码:

@Transactional(readOnly = true)public void changeInfo(){studentDao.updateAgeById(20,1);System.out.println("-----------");studentDao.updateNameById("test2",1);}

对应的事务异常(如果在只读状态下进行了非只读操作会引发下面的异常)


2.超时时间并回滚

属性名称:timeout

属性解释,在注解后同各国timeout = value实现如果超过value秒则会触发对应的异常。注意默认-1,表示无限长的限制时间。

案例代码:

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;@Transactional(timeout = 3)public void changeInfo(){//非只读方法studentDao.updateAgeById(20,1);System.out.println("-----------");//设置事务时间超过最长限制时间try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {throw new RuntimeException(e);}studentDao.updateNameById("test2",1);}
}

对应的事务异常(如果在超过事务的处理时间时候会引发下列异常)


3.指定事务异常

我们知道Exception异常有两个子类 分别是RuntimeException与IOException,而@Transaction异常在默认情况下只能够捕捉Runtime异常时候才会进行事务回滚,而如果发生了IOException异常则不会进行事务回滚

属性名称:rollbackFor (指定异常回滚)noRollBackFor(在指定异常范围内不进行回滚,基本不会使用)

案例代码:

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;
//     指定异常为Exception,即包含其所有子异常@Transactional(rollbackFor = Exception.class)public void changeInfo(){studentDao.updateAgeById(20,1);System.out.println("-----------");try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {throw new RuntimeException(e);}studentDao.updateNameById("test2",1);}
}

4.事务的隔离级别

事务可能会对数据进行修改,那么就会引发许多数据的问题,比如,脏读,幻读,不可重复读等问题。具体相关描述如下

  1. 脏读(Dirty Read): 脏读是指一个事务读取了另一个事务未提交的数据。假设有两个事务,事务A进行了修改但还未提交,事务B读取了事务A的修改后的数据,然后事务A回滚了。此时,事务B读取到的数据是无效或不一致的,这就是脏读。

  2. 幻读(Phantom Read): 幻读是指一个事务在同一个查询中多次进行读取,但是得到的结果集却不一致。假设事务A首先执行一个查询,返回了一些行,然后事务B插入了一些符合事务A查询条件的新行,接着事务A再次执行同样的查询,但结果集却发生了变化。这种情况下,事务A就发生了幻读,因为之前查询的结果集已经发生了变化。

  3. 不可重复读(Non-repeatable Read): 不可重复读是指在同一个事务中,多次读取同一条数据,但是得到的结果却不一致。假设事务A首先读取一条数据,然后事务B修改了该数据并提交,接着事务A再次读取同一条数据,发现结果与之前不同。这种情况下,事务A就遇到了不可重复读,因为同一条数据在事务执行期间发生了更改。

对此事务就有对应的隔离级别来避免相关问题的发生,但是注意,隔离级别越高,那么对应程序的性能将会越低。具体隔离级别如下

  • 读未提交(Read Uncommitted):事务可以读取未被提交的数据,容易产生脏读、不可重复读和幻读等问题。实现简单但不太安全,一般不用。
  • 读已提交(Read Committed):事务只能读取已经提交的数据,可以避免脏读问题,但可能引发不可重复读和幻读。
  • 可重复读(Repeatable Read):在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读的问题。
  • 串行化(Serializable):最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕之后才能执行另一个事务。可以避免以上所有问题,但效率较低,不适用于高并发场景。 不同的隔离级别适用于不同的场景,需要根据实际业务需求进行选择和调整。

事务属性名称:isolation

isolation的四个设置如下

隔离级别描述
READ UNCOMMITTED (读未提交)最低级别的隔离级别。它允许事务读取其他未提交事务所做的修改。可能出现脏读、幻读以及不可重复读。
READ COMMITTED (读已提交)事务只能读取已经提交的数据,不会读取未提交的数据。避免了脏读,但仍然可能出现幻读和不可重复读问题。
REPEATABLE READ (可重复读)事务在开始时读取一致的快照,并将该快照用于整个事务过程。确保了事务期间其他事务的插入操作不会影响到当前事务,但仍然可能出现幻读问题。
SERIALIZABLE (串行化)最高级别的隔离级别,保证事务串行执行,避免了脏读、幻读和不可重复读。所有并发事务按照顺序执行,但可能会牺牲一些并发性能。

注意:不同的数据库的默认事务隔离级别都是不同的,比如mysql就是第三级别。推荐设置第二级别即读已提交。

使用案例代码:

public class StudentService {@Autowiredprivate StudentDao studentDao;//设置为读已提交隔离级别@Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)public void changeInfo(){studentDao.updateAgeById(20,1);System.out.println("-----------");try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {throw new RuntimeException(e);}studentDao.updateNameById("test2",1);}
}

5. 事务的传播性

所谓的事务传播,即一个事务中调用了另一个事务,而对另一个事务是否加入原来事务还是独立出来单独的事务需要进行区分,则引入了事务的传播性来定义

属性:propagation

两个常用可选值:

传播属性描述
REQUIRED (默认值)如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务。这是大多数情况下的推荐选择,确保所有操作都在一个事务中执行。
REQUIRES_NEW创建一个新的事务,并挂起当前事务(如果存在)。新的事务独立于任何其他现有事务执行,并始终在自己的事务中操作。适用于需要完全独立的事务执行的场景。

 案例代码:

 //    设置为New 意味着算是一个独立的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)public void changeName(){studentDao.updateNameById("黄小浓",2);}@Transactional(propagation = Propagation.REQUIRED)public void changeAge(){studentDao.updateAgeById(55,2);}

这里具体解释一下是否独立意味着什么,如果独立了,那么如果在合并的事务中发生了异常,则事务将不会进行回滚,而在默认的Require的情况下,会先判断是否有其对应的父事务,如果没有才会进行创建事务。


本章总结

一、事务的种类

        1.认识编程式事务与声明式事务

二、Spring事务管理器

        1.认识几种常见的事务管理器

        2.熟悉并且会配置DataSourceTransactionManger事务管理器

三、事务注解使用

        1.熟悉@EnableTransactionManger、@Transaction注解

        2.熟悉事务注解的范围

四、事务属性

        1.熟悉事务的多种属性,比如只读(readonly)、超时时间(timeout)、指定异常、事务隔离级别、事务的传播

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/101839.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

typeScript学习笔记(一)

学习资源来自&#xff1a; 类与接口 TypeScript 入门教程 (xcatliu.com) 一.TypeScript的安装和运行 1.安装TypeScript 通过npm&#xff08;Node.js包管理器&#xff09;安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了Typ…

关于MyBatisPlus框架下出现xml里面定义的方法无法被正确识别以及提示调用mysql存储过程时参数无效的问题

第一个问题&#xff1a;xml里面明明定义了方法A&#xff0c;但是通过IService接口调用A的时候&#xff0c;总提示无法将接口中定义的函数绑定到xml中的同名方法中&#xff08;“Invalid bound statement (not found): com.aircas.sqlservice.mapper.SysTempIndexMapper.getRemo…

C++——智能指针

智能指针 文章目录 智能指针内存泄漏智能指针解决内存泄漏问题智能指针的使用及原理RAII智能指针对象的拷贝问题 C中的智能指针auto_ptrunique_ptrshared_ptrweak_ptr定制包装器C11和boost中智能指针的关系 内存泄漏 什么是内存泄漏&#xff1a;内存泄漏指因为疏忽或错误造成程…

Java多线程篇(1)——深入分析synchronized

文章目录 synchronized原理概述锁升级 初始状态偏向锁偏向锁获取/重入偏向锁的撤销/重偏向和升级批量重偏向和批量偏向撤销偏向锁的释放 轻量级锁轻量级锁获取/重入轻量级锁膨胀轻量级锁释放 重量级锁重量级锁获取/重入重量级锁释放重量级锁的降级 其他锁粗化、锁消除调用hashc…

看涨期权计算例题(期权案例计算)

看涨期权又称认购期权&#xff0c;买进期权&#xff0c;买方期权&#xff0c;买权&#xff0c;延买期权&#xff0c;或“敲进”&#xff0c;是指期权的购买者拥有在期权合约有效期内按执行价格买进一定数量标的物的权利&#xff0c;下文为大家科普看涨期权计算例题&#xff08;…

三维数字沙盘电子沙盘虚拟现实模拟推演大数据人工智能开发教程第15课

三维数字沙盘电子沙盘虚拟现实模拟推演大数据人工智能开发教程第15课 现在不管什么GIS平台首先要解决的就是数据来源问题&#xff0c;因为没有数据的GIS就是一个空壳&#xff0c;下面我就目前一些主流的数据获取 方式了解做如下之我见&#xff08;主要针对互联网上的一些卫星…

蓝桥杯官网填空题(土地测量)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 造成高房价的原因有许多&#xff0c;比如土地出让价格。既然地价高&#xff0c;土地的面积必须仔细计算。遗憾的是&#xff0c;有些地块的形状不规则&#xff0c;比…

【区块链 | IPFS】IPFS节点搭建、文件上传、节点存储空间设置、节点上传文件chunk设置

一、创建ipfs节点 通过ipfs init在本地计算机建立一个IPFS节点 本文有些命令已经执行过了&#xff0c;就没有重新初始化。部分图片拷贝自先前文档&#xff0c;具体信息应以实物为准 ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2048-bit RSA keypair.…

uniapp分包 解决分多个包的问题

1. 分包可以分很多个, 但是在"optimization": { "subPackages": true } 里面只能写一个, 2. 想分多个包 , 在 pages.json 里面 的 subPackages 里面继续加 第三个 第四个即可 3. 保存之后 创建页面就可以看见多个包了

数据可视化、BI和数字孪生软件:用途和特点对比

在现代企业和科技领域&#xff0c;数据起着至关重要的作用。为了更好地管理和理解数据&#xff0c;不同类型的软件工具应运而生&#xff0c;其中包括数据可视化软件、BI&#xff08;Business Intelligence&#xff09;软件和数字孪生软件。虽然它们都涉及数据&#xff0c;但在功…

CVE-2023-3836:大华智慧园区综合管理平台任意文件上传漏洞复现

文章目录 CVE-2023-3836&#xff1a;大华智慧园区综合管理平台任意文件上传漏洞复现0x01 前言0x02 漏洞描述0x03 影响范围0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 CVE-2023-3836&#xff1a;大华智慧园区综合管理平台任意文件上传漏洞复现 0x01 前言 免责声…

Lumion 和 Enscape 应该选择怎样的笔记本电脑?

Lumion 和 Enscape实时渲染对配置要求高&#xff0c;本地配置不够&#xff0c;如何快速解决&#xff1a; 本地普通电脑可一键申请高性能工作站&#xff0c;资产安全保障&#xff0c;供软件中心&#xff0c;各种软件插件一键获取&#xff0c;且即开即用&#xff0c;使用灵活&am…