Spring-tx事务管理

第五章 Spring声明式事务

一 声明式事务概念

1.1 编程式事务

手动编写程序来管理事务,即通过编写代码的方式来实现事务的提交,和回滚。

1.2 声明式事务

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

开发者只需要添加注解或者配置文件,具体的实现通过框架来实现。

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

1.3Spring事务管理器

  1. Spring声明式事务对应依赖

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

我们现在要使用的事务管理器是org.springframework.jdbc.datasource.DataSourceTransactionManager,将来整合 JDBC方式、JdbcTemplate方式、Mybatis方式的事务实现!

DataSourceTransactionManager类中的主要方法:

  • doBegin():开启事务
  • doSuspend():挂起事务
  • doResume():恢复挂起的事务
  • doCommit():提交事务
  • doRollback():回滚事务

1.4 Spring-tx

Spring-tx声明式事务的实现。

spring-tx提供了事务管理器的接口,但是没有实现类。没有实现类的原因是,对数据库操作的技术有很多如jdbc,dbutils,jdbcTemplate,mybatis,hibernate等。不同技术对应的事务方法也不一样。spring就没有提供实现类。

但是在其他包中有事务管理器的接口,根据对数据库操作使用的技术,来选择合适的实现类。

如spring-jdb包中的DataSourceTM 类是连接形事务,如jdbc,jdbcTemplate ,mybatis。

作为声明式事务,我们需要做的事情。一选择合适的事务管理器接口的实现类,二选择要事务管理的方法。

1.5 搭建环境

dao层

@Repository
public class StudentDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void updateNameById(String name,Integer id){String sql = "update students set name = ? where id = ? ;";int rows = jdbcTemplate.update(sql, name, id);}public void updateAgeById(Integer age,Integer id){String sql = "update students set age = ? where id = ? ;";jdbcTemplate.update(sql,age,id);}
}

service层

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

配置类

@Configuration
@ComponentScan({"com.ls.service","com.ls.dao"})
@PropertySource("classpath:jdbc.properties")
public class MainConfig {@Value("${jdbc.url}")private String url;@Value("${jdbc.driver}")private String driver;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setUrl(url);druidDataSource.setDriverClassName(driver);druidDataSource.setUsername(username);druidDataSource.setPassword(password);return  druidDataSource;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}
}

测试

@SpringJUnitConfig(MainConfig.class)
public class SpringTest {@Autowiredprivate StudentService studentService;@Testpublic void test(){studentService.changeInfo();}
}

环境成功。

二 spring-tx的使用

  1. 将合适的事务管理器实现类装入ioc容器中
 /*** 装配事务管理实现对象* @param dataSource* @return*/@Beanpublic TransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}
  1. 开启事务注解支持,编写注解

在配置类上添加 @EnableTransactionManagement。开始事务注解支持。

在需要添加事务的方法上添加@Transactional

@Transcational也可以加加在类上,这样类上的所有方法都有事务。

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;@Transactionalpublic void changeInfo(){studentDao.updateAgeById(100,1);int i = 1 / 0;System.out.println("-----------");studentDao.updateNameById("test2",1);}
}

2.1 只读模式

  • 只读模式 根据属性 readOnly = false (默认),开启只读模式可以提升查询效率。
  • 但是一般查询没有必要添加事务,为什么还有只读模式?
  • 因为有时候事务是添加在类上了,类中的查询方法要想提升效率,可以使用只读模式。
@Service
@Transactional
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** 1. 只读模式 根据属性 readOnly = false 默认*      开启只读模式可以提升查询效率.*      但是一般查询没有必要添加事务,为什么还有只读模式*      因为有时候事务是添加在类上了,类中的查询方法要想提升效率,可以使用只读模式。**/public void changeInfo(){studentDao.updateAgeById(1000,1);System.out.println("-----------");studentDao.updateNameById("test222",1);}@Transactional(readOnly = true)public void getInfo(){//查询}
}

2.2 超时时间

  1. 需求

事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。

此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。

概括来说就是一句话:超时回滚,释放资源。

  1. 设置超时时间

timeout 默认:-1,永不超时。

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!*/@Transactional(readOnly = false,timeout = 3)public void changeInfo(){studentDao.updateAgeById(100,1);//休眠4秒,等待方法超时!try {Thread.sleep(4000);} catch (InterruptedException e) {throw new RuntimeException(e);}studentDao.updateNameById("test1",1);}
}
  1. 测试超时效果

执行抛出事务超时异常

org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Wed May 24 09:10:43 IRKT 2023at org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:155)at org.springframework.transaction.support.ResourceHolderSupport.getTimeToLiveInMillis(ResourceHolderSupport.java:144)at org.springframework.transaction.support.ResourceHolderSupport.getTimeToLiveInSeconds(ResourceHolderSupport.java:128)at org.springframework.jdbc.datasource.DataSourceUtils.applyTimeout(DataSourceUtils.java:341)at org.springframework.jdbc.core.JdbcTemplate.applyStatementSettings(JdbcTemplate.java:1467)
  • 需要注意的是如果在类上设置了超时时间,但是在方法上有重新设置了事务,此时方法上的事务会覆盖类上的事务。如果类上事务设置了超时时间,但是方法上设置事务,但是没设置超时时间,此时就该方法的事务就无超时间。

2.3事务属性:事务异常

  1. 默认情况

默认只针对运行时异常回滚,编译时异常不回滚。情景模拟代码如下:

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!*/@Transactional(readOnly = false,timeout = 3)public void changeInfo() throws FileNotFoundException {studentDao.updateAgeById(100,1);//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内! new FileInputStream("xxxx");studentDao.updateNameById("test1",1);}
}
  1. 设置回滚异常

rollbackFor属性:指定哪些异常类才会回滚,默认是 RuntimeException and Error 异常方可回滚!

/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!*/
@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class)
public void changeInfo() throws FileNotFoundException {studentDao.updateAgeById(100,1);//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内! new FileInputStream("xxxx");studentDao.updateNameById("test1",1);
}
  1. 设置不回滚的异常

在默认设置和已有设置的基础上,再指定一个异常类型,碰到它不回滚。

noRollbackFor属性:指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!

@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!*/@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class)public void changeInfo() throws FileNotFoundException {studentDao.updateAgeById(100,1);//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!new FileInputStream("xxxx");studentDao.updateNameById("test1",1);}
}

2.4 事务属性:事务隔离级别

  1. 事务隔离级别

数据库事务的隔离级别是指在多个事务并发执行时,数据库系统为了保证数据一致性所遵循的规定。常见的隔离级别包括:

  1. 读未提交(Read Uncommitted):事务可以读取未被提交的数据,容易产生脏读、不可重复读和幻读等问题。实现简单但不太安全,一般不用。2. 读已提交(Read Committed):事务只能读取已经提交的数据,可以避免脏读问题,但可能引发不可重复读和幻读。3. 可重复读(Repeatable Read):在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读的问题。4. 串行化(Serializable):最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕之后才能执行另一个事务。可以避免以上所有问题,但效率较低,不适用于高并发场景。
  1. 事务隔离级别设置
package com.atguigu.service;import com.atguigu.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;import java.io.FileInputStream;
import java.io.FileNotFoundException;/*** projectName: com.atguigu.service*/
@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!* isolation = 设置事务的隔离级别,mysql默认是repeatable read!*/@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class,isolation = Isolation.REPEATABLE_READ)public void changeInfo() throws FileNotFoundException {studentDao.updateAgeById(100,1);//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!new FileInputStream("xxxx");studentDao.updateNameById("test1",1);}
}

2.5 事务属性:事务传播行为

  1. 事务传播行为要研究的问题

举例代码:

@Transactional
public void MethodA(){// ...MethodB();// ...
}//在被调用的子方法中设置传播行为,代表如何处理调用的事务! 是加入,还是新事务等!
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void MethodB(){// ...
}
  1. propagation属性

@Transactional 注解通过 propagation 属性设置事务的传播行为。它的默认值是:

Propagation propagation() default Propagation.REQUIRED;
  propagation 属性的可选值由 org.springframework.transaction.annotation.Propagation 枚举类提供:
名称含义
REQUIRED  默认值如果父方法有事务,就加入,如果没有就新建自己独立!
REQUIRES_NEW不管父方法是否有事务,我都新建事务,都是独立的!
  1. 测试

    1. 声明两个业务方法
@Service
public class StudentService {@Autowiredprivate StudentDao studentDao;/*** timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!* isolation = 设置事务的隔离级别,mysql默认是repeatable read!*/@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class,isolation = Isolation.REPEATABLE_READ)public void changeInfo() throws FileNotFoundException {studentDao.updateAgeById(100,1);//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!new FileInputStream("xxxx");studentDao.updateNameById("test1",1);}/*** 声明两个独立修改数据库的事务业务方法*/@Transactional(propagation = Propagation.REQUIRED)public void changeAge(){studentDao.updateAgeById(99,1);}@Transactional(propagation = Propagation.REQUIRED)public void changeName(){studentDao.updateNameById("test2",1);int i = 1/0;}}
  2. 声明一个整合业务方法
@Service
public class TopService {@Autowiredprivate StudentService studentService;@Transactionalpublic void  topService(){studentService.changeAge();studentService.changeName();}
}
  3. 添加传播行为测试
@SpringJUnitConfig(classes = AppConfig.class)
public class TxTest {@Autowiredprivate StudentService studentService;@Autowiredprivate TopService topService;@Testpublic void  testTx() throws FileNotFoundException {topService.topService();}
}
  **注意:**在同一个类中,对于@Transactional注解的方法调用,事务传播行为不会生效。这是因为Spring框架中使用代理模式实现了事务机制,在同一个类中的方法调用并不经过代理,而是通过对象的方法调用,因此@Transactional注解的设置不会被代理捕获,也就不会产生任何事务传播行为的效果。
  1. 其他传播行为值(了解)

    1. Propagation.REQUIRED:如果当前存在事务,则加入当前事务,否则创建一个新事务。
    2. Propagation.REQUIRES_NEW:创建一个新事务,并在新事务中执行。如果当前存在事务,则挂起当前事务,即使新事务抛出异常,也不会影响当前事务。
    3. Propagation.NESTED:如果当前存在事务,则在该事务中嵌套一个新事务,如果没有事务,则与Propagation.REQUIRED一样。
    4. Propagation.SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务方式执行。
    5. Propagation.NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,挂起该事务。
    6. Propagation.MANDATORY:必须在一个已有的事务中执行,否则抛出异常。
    7. Propagation.NEVER:必须在没有事务的情况下执行,否则抛出异常。

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

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

相关文章

陇剑杯 流量分析 webshell CTF writeup

陇剑杯 流量分析 链接:https://pan.baidu.com/s/1KSSXOVNPC5hu_Mf60uKM2A?pwdhaek 提取码:haek目录结构 LearnCTF ├───LogAnalize │ ├───linux简单日志分析 │ │ linux-log_2.zip │ │ │ ├───misc日志分析 │ │ …

[SWPUCTF 2021 新生赛]error

如果 flag 只出现一半,用substr(A,B,C) 查询flag 1 and (select extractvalue(1,concat(~,(select substr((select flag from test_tb), 1 , 31))))) # 0-30位 左边30位 1and (select extractvalue(1,concat(~,(select substr((select flag from test_tb), 31 , 6…

vivado 设置 VIO 核以执行测量、查看 VIO 核状态

设置 VIO 核以执行测量 您添加到自己的设计中的 VIO 核会显示在“硬件 (Hardware) ”窗口中的目标器件下。如果未显示这些 VIO 核 , 请右键 单击器件并选择“ Refresh Hardware ”。这样将重新扫描 FPGA 或 ACAP 并刷新“ Hardware ”窗口。 注释 &#xff…

阿里云4核8G云服务器价格多少钱?700元1年

阿里云4核8G云服务器价格多少钱?700元1年。阿里云4核8G服务器租用优惠价格700元1年,配置为ECS通用算力型u1实例(ecs.u1-c1m2.xlarge)4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选,CPU采用Intel(R) Xeon(R…

久吾高科技股份有限将莅临2024第13届生物发酵展

参展企业介绍 江苏久吾高科技股份有限公司成立于1997年,是一家专注从事新材料研发与整体解决方案的高科技企业。2017年3月在深交所A股创业板上市。公司是首批认定的guojiaji高新技术企业、国家专精特新“小巨人”企业、国家制造业单项、中国膜行业陶瓷膜领域龙头企…

使用vite从头搭建一个vue3项目(三)vite.config.js配置

目录 一、声明环境变量配置文件二、vite.config.js基础配置1、defineConfig()、loadEnv()2、plugins配置项3、server配置项4、resolve配置项5、css配置项6、build配置项 三、vite.config.js配置完整代码 VITE版本:v5.2.8 一、声明环境变量配置文件 在根目录下新建…

Qt 系统相关

这里写目录标题 Qt 事件事件介绍事件的处理按键事件单个按键组合按键 ⿏标事件⿏标单击事件⿏标释放事件⿏标双击事件⿏标移动事件滚轮事件 定时器QTimerEvent 类QTimer 类获取系统⽇期及时间 事件分发器概述事件分发器⼯作原理 事件过滤器 Qt ⽂件Qt ⽂件概述输⼊输出设备类⽂…

GPT国内怎么用?4月最新版本来了

ChatGPT镜像 今天在知乎看到一个问题:“平民不参与内测的话没有账号还有机会使用ChatGPT吗?” 从去年GPT大火到现在,关于GPT的消息铺天盖地,真要有心想要去用,途径很多,别的不说,国内GPT的镜像…

HarmonyOS开发实例:【任务延时调度】

介绍 本示例使用[ohos.WorkSchedulerExtensionAbility] 、[ohos.net.http]、[ohos.notification] 、[ohos.bundle]、[ohos.fileio] 等接口,实现了设置后台任务、下载更新包 、保存更新包、发送通知 、安装更新包实现升级的功能。 效果预览 使用说明 安装本应用之…

数字乡村探索:引领农村未来发展新方向——科技创新赋能乡村现代化与农民生活品质提升之旅

目录 一、数字乡村的内涵与特点 二、数字乡村的探索进展 三、数字乡村面临的挑战与机遇 四、数字乡村的未来发展方向与路径 五、数字乡村助力农村产业升级 六、数字乡村促进城乡融合发展 七、数字乡村激发农民创新创业活力 八、数字乡村提升农民获得感和幸福感 九、展…

Postman还能做Mock?又学了一招!

1、什么是mock测试 Mock 测试就是在测试活动中,对于某些不容易构造或者不容易获取的数据/场景,用一个Mock对象来创建以便测试的测试方法。 2、Mock测试常见场景 无法控制第三方系统接口的返回,返回的数据不满足要求 依赖的接口还未开发完成…

Scala 02——Scala OOP

文章目录 Scala 02——Scala OOP前序类1. 类的基本结构2. 普通类和数据类的区别 继承1. extends2. override 抽象类抽象类的特点 单例对象1. 定义2. 场景3. 方法3.1 方法定义3.2 方法调用 特质1. 抽象类和特质的区别2. 强制混入语法3. 静态混入和动态混入 内部类Java和Scala内部…

【C语言】贪吃蛇项目(1) - 部分Win32 API详解 及 贪吃蛇项目思路

文章目录 一、贪吃蛇项目需要实现的基本功能二、Win32 API介绍2.1 控制台2.2 部分控制台命令及调用函数mode 和 title 命令COORD 命令GetStdHandle(获取数据)GetConsoleCursorInfo(获取光标数据)SetConsoleCursorInfo &#xff08…

蓝桥杯(基础题)

试题 C: 好数 时间限制 : 1.0s 内存限制: 256.0MB 本题总分:10 分 【问题描述】 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位 )上 的数字是奇数,偶数位(十位、千位、十万位 &…

PhotoShop2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Adobe Photoshop是一款由Adobe Systems开发的图像编辑软件。它被广泛用于图像处理和数字艺术创作,是设计师、摄影师和艺术家们的首选工具之一。 主要功能: 图像编辑: Photoshop提供了丰富的编辑…

激光共聚焦显微镜测粗糙度,解读表面粗糙度的科技利器

激光共聚焦显微镜(Laser Scanning Confocal Microscope,简称LSCM)是一种光学显微镜,通过激光束的聚焦和散射技术,能够实现高分辨率的三维图像采集和表面测量。其在科学研究、工程领域等领域有着广泛的应用,…

【环境搭建】(五)Ubuntu22.04安装cuda_11.8.0+cudnn_8.6.0

一个愿意伫立在巨人肩膀上的农民...... 设备配置: 一、安装GCC 安装cuda之前,首先应该安装GCC,安装cuda需要用到GCC,否则报错。可以先使用下方指令在终端查看是否已经安装GCC。 gcc --version 如果终端打印如下则说明已经安装…

使用SpringBoot将中国地震台网数据保存PostGIS数据库实践

目录 前言 一、数据转换 1、Json转JavaBean 2、JavaBean与数据库字段映射 二、空间数据表设计 1、表结构设计 三、PostGIS数据保存 1、Mapper接口定义 2、Service逻辑层实现 3、数据入库 4、运行实例及结果 总结 前言 在上一篇博客中基于Java的XxlCrawler网络信息爬…

c++的学习之路:23、多态(2)

摘要 多态的抽象类、原理以及虚表。 目录 摘要 一、抽象类 1、 概念 2、接口继承和实现继承 二、多态的原理 1、虚函数表 2、动态绑定与静态绑定 三、单继承和多继承关系的虚函数表 1、单继承中的虚函数表 2、多继承中的虚函数表 四、思维导图 一、抽象类 1、 概…

消息中间件Kafka分布式数据处理平台

目录 一.Kafka基本介绍 1.定义 2.特点 (1)高吞吐量、低延迟 (2)可扩展性 (3)持久性、可靠性 (4)容错性 (5)高并发 3.系统架构 (1&#…