【Spring】事务
【Spring】事务
文章目录
- 【Spring】事务
- 一、概念
- 1.什么是事务
- 2.事务的四个特性(ACID)
- 二、事务操作
- 1.基本流程
- 2.Spring 事务管理介绍
- 3.声明式事务管理(基于注解)
- 3.声明式事务管理(基于 XML)
事务是数据库操作的最基本单元
一、概念
1.什么是事务
事务(Transaction)是数据库操作的最基本单元
2.事务的四个特性(ACID)
原子性(Atomicity)
一个原子事务要么完整执行,要么全部全部回滚一致性(Consistency)
一致性代表了底层数据存储的完整性。它必须由事务系统和应用开发人员共同来保证。事务系统通过保证事务的原子性、隔离性和持久性来满足这一要求;而应用开发人员需要保证数据库有适当的约束(主键、引用、完整性等),并且工作单元中所实现的业务逻辑不会导致数据的不一致。例如,在转账过程中,从某一账户扣除的金额必须与另一账户存入的金额相等隔离性(Isolation)
隔离性意味着事务必须在不干扰其它进程或事务的前提下独立执行。换言之,在事务或工作单元执行完毕之前,其访问的数据不能受系统其它部分的影响持久性(Durability)
持久性表示在某个事务的执行过程中,对数据所做的所有改动都必须在事务成功结束前保存至某种物理存储设备。这样可以保证,所做的修改在任何系统瘫痪时不至于丢失
二、事务操作
1.基本流程
public String insertUser(UserEntity userEntity){try{int j = userMapper.insertUser(userEntity); //插入数据到数据库,但还未提交事务int i = 1 / 0; //模拟出现异常,被捕获return "ok"; //出现异常,不会返回 ok,也不会提交事务}catch(Exception e){回滚操作; //捕获到异常,不能提交事务,必须回滚之前的插入操作return "fail"; //回滚完成,返回 fail}
}
2.Spring 事务管理介绍
事务添加到 Java EE 三层结构中的 Service 层
Spring 的事务管理操作分为两种
编程式事务管理
需要在代码中显式调用 beginTransaction()、commit()、rollback() 等事务管理相关的方法声明式事务管理
Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需要在配置文件中做相关的事务规则声明(或者基于注解的方式),便可以将事务规则应用到业务逻辑中。因为事务管理本身就是一个典型的横切逻辑,正是 AOP 的用武之地
通常情况下,强烈建议在开发中使用声明式事务管理,不仅因为其简单,更主要是因为这样使得业务代码不被污染,极大方便后期的代码维护。相较于编程式事务,唯一的不足是声明式事务的最细粒度只能作用到方法级别,无法作用到代码块级别。但是即便有这样的需求,也可以将需要进行事务管理的代码块独立为方法来解决
声明式事务管理有两种实现方式
- 基于注解
- 基于 XML 配置文件
3.声明式事务管理(基于注解)
第一步 在 Spring 配置文件中配置持久层框架(以 JDBCTemplate 为例)
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"destroy-method="close"><property name="url" value="jdbc:mysql:///user_db" /><property name="username" value="root" /><property name="password" value="root" /><property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean><!-- JdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
第二步 在 Spring 配置文件中配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property>
</bean>
第三步 在 Spring 配置文件中引入命名空间 tx
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
第四步 在 Spring 配置文件中开启事务注解
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
第五步 在 Service 类上添加事务注解
@Service
@Transactional
public class UserService {...
}
@Transactional 也可以添加到方法上,添加到类上表示为类里的所有方法添加事务,添加到方法上表示为这个方法添加事务
我们也可以不写任何 XML 文件,写一个配置类,使用注解来开启组件扫描、配置持久层框架、创建事务管理器和开启事务注解
@Configuration
@ComponentScan(basePackages = "com.sisyphus") //开启组件扫描
@EnableTransactionManagement //开启事务注解
public class TxConfig {//创建数据库连接池@Beanpublic DruidDataSource getDruidDataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///user_db");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;}//创建 JDBCTemplate 对象@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource) {//到 ioc 容器中根据类型找到 dataSourceJdbcTemplate jdbcTemplate = new JdbcTemplate();//注入 dataSourcejdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//创建事务管理器@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}
}
参数配置
在 @Transactional 注解里面可以配置事务相关参数
1、propagation 事务传播行为
事务传播行为用来描述,某一个被添加事务的方法被嵌套进另一个方法时事务如何传播
Spring 定义了 7 种事务传播行为
- REQUIRED
如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行 - REQUIRED_NEW
当前的方法必须启动新事务,并在它自己的事务内运行。如果有事务正在运行,将它挂起 - SUPPORTS
如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 - NOT_SUPPORTED
当前的方法不应该运行在事务中,如果有运行的事务,将它挂起 - MANDATORY
当前的方法必须运行在事务中,如果没有正在运行的事务,就抛出异常 - NEVER
当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常 - NESTED
如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则,就启动一个新的事务,并在它自己的事务内运行
2、ioslation 事务隔离级别
在并发操作中,事务在执行完毕前,其访问的数据可能会被其它事务影响
这种影响具体表现为三个读问题
脏读:当前事务中读到其他事务未提交的数据,也就是脏数据
以上图为例,事务 A 在读取文章的阅读量时,读取到了事务B为提交的数据。如果事务 B 最后没有顺利提交,导致事务回滚,那么实际上阅读量并没有修改成功,而事务A却是读到的修改后的值,显然不合情理
不可重复读:在事务 A 中先后两次读取同一个数据,但是两次读取的结果不一样。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据
以上图为例,事务 A 在先后读取文章阅读量的数据时,结果却不一样。说明事务 A 在执行的过程中,阅读量的值被其它事务给修改了。这样使得数据的查询结果不再可靠,同样也不合实际
幻读:在事务 A 中按照某个条件先后两次查询数据库,两次查询结果的行数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了
以上图为例,当对 0 < 阅读量 < 100 的文章进行查询时,先查到了一个结果,后来查询到了两个结果。这表明同一个事务的查询结果数不一,行数不一致。这样的问题使得在根据某些条件对数据筛选的时候,前后筛选结果不具有可靠性
通过设置事务隔离性可以解决上述问题
默认为可重复读
3、timeout 超时时间
事务需要在一定时间内进行提交,如果不提交就进行回滚
默认值为 -1(表示不限制超时时间),时间以秒单位
4、readOnly 是否只读
- 读:查询
- 写:增删改
默认值 false,表示可以读写,设置成 true 后只能读
5、rollbackFor 回滚
设置出现哪些异常进行事务回滚
6、noRollbackFor 不回滚
设置出现哪些异常不进行事务回滚
3.声明式事务管理(基于 XML)
第一步 在 Spring 配置文件中配置事务管理器
(与注解开发相关代码一样)
第二步 在 Spring 配置文件中配置通知(即事务)
<!-- 配置通知-->
<tx:advice id="txadvice"><!--配置事务参数--><tx:attributes><!--指定在哪些方法上面添加事务,可以是方法名,也可以是某种规则 如 "account*" 表示以 account 开头的方法名 --><!--还可以进行参数配置--><tx:method name="accountMoney" propagation="REQUIRED"/></tx:attributes>
</tx:advice>
第三步 在 Spring 配置文件中配置切入点和切面
需要引入命名空间 aop
<!--3 配置切入点和切面-->
<aop:config><!--配置切入点--><aop:pointcut id="pt" expression="execution(* com.sisyphus.service.UserService.*(..))"/><!--配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
我们主要还是使用注解开发,这种方式很少会用
【Spring】事务相关推荐
- (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
- spring的事务隔离_再深一点:面试工作两不误,源码级理解Spring事务
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...
- spring上下文是什么意思_Java程序员只会CRUD连Spring事务传播机制都不懂?
AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东西,面试完就 ...
- Spring事务管理的底层逻辑—源码解析
本文代码为spring 5.1.2 spring是如何控制事务的提交和回滚 加上@Transactional注解之后,Spring可以启到事务控制的功能了,再正式执行方法前它会做一些操作,我们来看看 ...
- springboot 事务手动回滚_来,讲讲Spring事务有哪些坑?
来自公众号:孤独烟 引言 今天,我们接上文<面试官:谈谈你对mysql事务的认识>的内容,来讲spring中和事务有关的考题! 因为事务这块,面试的出现几率很高.而大家工作中CRUD的比较 ...
- Spring事务管理 与 SpringAOP
1,Spring事务的核心接口 Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略. ...
- Spring 事务失效?看这篇文章就够了!
欢迎关注方志朋的博客,回复"666"获面试宝典 用 Spring 的 @Transactional 注解控制事务有哪些不生效的场景? 不知道小伙伴们有没有这样的经历,在自己开心的编 ...
- 面试官: 讲讲 Spring 事务有哪些坑?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 引言 今天,我们来讲 Spring 中和事务有关的考题. ...
- 一文带你看懂Spring事务!
点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 前言 Spring事务管理我相信大家都用得很多,但可能仅仅局限于一个@Transactiona ...
- java 封装事务_Spring之路(36)–事务很重要吗?Spring为何要封装事务?Spring事务有陷阱吗?...
可以不使用事务吗 真的遇到过开发企业应用,但是不知道啥是事务的朋友. 好吧,我始终认为抛开性能.界面.易用性等方面不说,正确性应该是一个项目最基础的要求了. 所以,凡是企业应用,正儿八经有客户的系统, ...
最新文章
- UE4材质:纯数学算法实现水面水波扩散效果
- linux-shell面试题 之二
- JDG战队与英特尔达成为期两年的冠名合作
- php评论倒序 zblog_ZblogPHP调用最新、评论最多、浏览最多、置顶文章
- 中国计算机学会推荐国际学术会议和期刊目录(2015 年)
- LoadRunner视频教程地址
- linux系统怎么数据恢复,linux系统数据恢复
- 固定定位相对于当前父元素
- 烤仔的朋友们丨Totle 是什么?
- virtualenv虚拟环境中安装MySQL-python
- 使用SmartUpload组件上传文件,自己踩过的坑
- [数读]从开户数看这一波牛市
- 山羊拉丁文 - [Python3]
- 逆战之总结常见的react组件
- 服务器修改远程链接端口号,怎么修改服务器的远程连接端口号
- 计算机概念入门(一)
- 常用linux系统扫描命令汇总
- 一个小学弟问我的算法问题
- 集创赛备赛:Robei八角板7020简介
- idea必装插件介绍