一、什么是事务

维基百科:
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
理解:
事务(Transaction)是数据库区别于文件系统的重要特性之一。传统关系型数据库设计原则是满足 ACID特性,用以保证数据库事务的正确执行。Mysql的innoDB引擎就很好的支持了ACID。

二、事务的ACID特性

(箭头后,翻译自官网介绍:InnoDB and the ACID Model

1,原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。--》主要涉及InnoDB事务。相关特性:事务的提交,回滚,信息表。

2,一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。在事务开始前后,数据库的完整性约束没有被破坏。例如违反了唯一性,必须撤销事务,返回初始状态。--》主要涉及内部InnoDB处理,以保护数据不受崩溃,相关特性:双写缓冲、崩溃恢复。

3,隔离性(isolation):每个读写事务的对象对其他事务的操作对象能相互分离,即:事务提交前对其他事务是不可见的,通常内部加锁实现。--》主要涉及事务,尤其是事务隔离级别,相关特性:隔离级别、innodb锁的底层实现细节。

4,持久性(durability):一旦事务提交,则其所做的修改会永久保存到数据库。--》涉及到MySQL软件特性与特定硬件配置的相互影响,相关特性:4个配置项:双写缓冲开关、事务提交刷新log的级别、binlog同步频率、表文件;写缓存、操作系统对于fsync()的支持、备份策略等。

The database remains in a consistent state at all times — after each commit or rollback, and while transactions are in progress.

If related data is being updated across multiple tables, queries see either all old values or all new values, not a mix of old and new values.(摘自MYSQL官网ACID中一致性状态的描述)
数据库在事务的提交、回滚,或运行中,总是处于一个一致的状态。

如果关联数据跨多张表更新,查询时只能看见全老数据/全新数据,而不是新老数据混合。

The consistency aspect of the ACID model mainly involves internal InnoDB processing to protect data from crashes.

Related MySQL features include: InnoDB doublewrite buffer. InnoDB crash recovery. (摘自MYSQL-一致性特性)
ACID模型的一致性方面主要涉及内部InnoDB处理,以保护数据不受崩溃影响。MySQL相关特性包括: 双写缓冲、崩溃恢复。

三、事务的属性

要保证事务的ACID特性,spring给事务定义了6个属性,对应于声明式事务注解(org.springframework.transaction.annotation.Transactional)@Transactional(key1=*,key2=*...)

事务名称:用户可手动指定事务的名称,当多个事务的时候,可区分使用哪个事务。对应注解中的属性value、transactionManager
隔离级别: 为了解决数据库容易出现的问题,分级加锁处理策略。 对应注解中的属性isolation
超时时间: 定义一个事务执行过程多久算超时,以便超时后回滚。可以防止长期运行的事务占用资源.对应注解中的属性timeout
是否只读:表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务.对应注解中的属性readOnly
传播机制: 对事务的传播特性进行定义,共有7种类型。对应注解中的属性propagation
回滚机制:定义遇到异常时回滚策略。对应注解中的属性rollbackFor、noRollbackFor、rollbackForClassName、noRollbackForClassName
其中隔离级别和传播机制比较复杂,咱们细细地品一品

3.1 隔离级别

这一块比较复杂,我们从3个角度来看:3种错误现象、mysql的底层技术支持、分级处理策略。这一小节一定要好好看,已经开始涉及核心原理了。

1.现象(三种问题)
脏读(Drity Read):事务A更新记录但未提交,事务B查询出A未提交记录。

不可重复读(Non-repeatable read): 事务A读取一次,此时事务B对数据进行了更新或删除操作,事务A再次查询数据不一致。

幻读(Phantom Read): 事务A读取一次,此时事务B插入一条数据,事务A再次查询,记录多了。

2. mysql的底层支持(IndoDB事务模型)(一致性非锁定读VS锁定读)
官网飞机票:InnoDB Transaction Model

两种读
在MVCC中,读操作可以分成两类,快照读(Snapshot read)和当前读(current read)。

快照读:普通的select * from

当前读:

select * from table where ? lock in share mode; (加S锁)
select * from table where ? for update; (加X锁)
insert, update, delete 操作前会先进行一次当前读(加X锁)
其中前两种锁定读,需要用户自己显式使用,最后一种是自动添加的。

   1.一致性非锁定读(快照读)

一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(multi versionning)的方式来读取当前执行时间数据库中行的数据,如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此等待行上锁的释放。相反的,InnoDB会去读取行的一个快照数据

上面展示了InnoDB存储引擎一致性的非锁定读。之所以称为非锁定读,因为不需要等待访问的行上X锁的释放。快照数据是指该行之前版本的数据,该实现是通过undo段来完成。而undo用来事务中的回滚数据,因此快照数据本身没有额外的开销,此外,读取快照数据不需要上锁,因为没有事务需要对历史数据进行修改操作。

   2.锁定读

三种锁
1,Record Lock(行级锁):
1)共享锁:S Lock,允许事务读取一行数据。
2)排它锁:X Lock,允许事务删除或更新一行数据。
注:只有S+S是兼容的,其它3种组合都是不兼容的。

2,Gap Lock(间隙锁):锁定一个范围,不包含记录本身。

3,Next-Key Lock(下一键锁):Gap Lock + Record Lock,锁定范围和记录本身。

innoDB对select语句支持两种锁定读:

1)SELECT...FOR UPDATE:对读取的行加排它锁(X锁),其他事务不能对已锁定的行再加任何锁。

2 ) SELECT...LOCK IN SHARE MODE :对读取的行加共享锁(S锁),其他事务可以再加S锁,X锁会阻塞等待。

注:这两种锁都必须处于事务中,事务commit,锁释放。所以必须begin或者start transaction 开启一个事务或者索性set autocommit=0把自动提交关掉(mysql默认是1,即执行完sql立即提交)

3. 分级处理策略(四种隔离级别)
官网描述:

InnoDB使用不同的锁定策略支持每个事务隔离级别。对于关键数据的操作(遵从ACID原则),您可以使用强一致性(默认Repeatable Read)。对于不是那么重要的数据操作,可以使用Read Committed/Read Uncommitted。Serializable执行比可重读更严格的规则,用于特殊场景:XA事务,并发性和死锁问题的故障排除。

四种隔离级别:

1.Read Uncommitted(读未提交内容):可能读取其它事务未提交的数据。-脏读问题(脏读+不可重复读+幻读)

2.Read Committed(读已提交内容):一个事务只能看见已经提交事务所做的改变。其它事务commit,当前事务中多次查询可能返回不同结果。(不可重复读+幻读)

select...from : 一致性非锁定读的数据快照(MVCC)是最新版本的,但其他事务可能会有新的commit,所以同一select可能返回不同结果。-不可重复读问题
select...from for update : record lock行级锁.

3.Repeatable Read(可重读):

select…from :同一事务内多次一致性非锁定读,取第一次读取时建立的快照版本(MVCC),保证了同一事务内部的可重复读.—狭义的幻读问题得到解决。(Db插入了数据,只不过读不到)

select...from for update (FOR UPDATE or LOCK IN SHARE MODE), UPDATE, 和 DELETE : next-key lock下一键锁.

  1)对于具有唯一搜索条件的唯一索引,innoDB只锁定找到的索引记录. (next-key lock 降为record lock)

  2)对于其他非索引或者非唯一索引,InnoDB会对扫描的索引范围进行锁定,使用next-key locks,阻塞其他session对间隙的insert操作,-彻底解决广义的幻读问题。(DB没插入数据)

4.Serializable(可串行化):这是最高的隔离级别,它是在每个读的数据行上加上共享锁(LOCK IN SHARE MODE)。在这个级别,可能导致大量的超时现象和锁竞争,主要用于分布式事务。

如下表:

3.2 传播机制

org.springframework.transaction包下有一个事务定义接口TransactionDefinition,定义了7种事务传播机制,很多人对传播机制的曲解从概念开始,所以特地翻译了一下源码注释如下:

关于EJB事务,可参考,EJB 是用于组件开发的一个框架,EJB 架构支持分布式事务。

1.PROPAGATION_REQUIRED

支持当前事务;如果不存在,创建一个新的。类似于同名的EJB事务属性。这通常是事务定义的默认设置,通常定义事务同步作用域。

2.PROPAGATION_SUPPORTS

支持当前事务;如果不存在事务,则以非事务方式执行。类似于同名的EJB事务属性。

注意:对于具有事务同步的事务管理器,PROPAGATION_SUPPORTS与没有事务稍有不同,因为它可能在事务范围内定义了同步。因此,相同的资源(JDBC的Connection、Hibernate的Session等)将在整个指定范围内共享。注意,确切的行为取决于事务管理器的实际同步配置!

小心使用PROPAGATION_SUPPORTS!特别是,不要依赖PROPAGATION_REQUIRED或PROPAGATION_REQUIRES_NEW,在PROPAGATION_SUPPORTS范围内(这可能导致运行时的同步冲突)。如果这种嵌套不可避免,请确保适当地配置事务管理器(通常切换到“实际事务上的同步”)。

3.PROPAGATION_MANDATORY

支持当前事务;如果当前事务不存在,抛出异常。类似于同名的EJB事务属性。

注意:PROPAGATION_MANDATORY范围内的事务同步总是由周围的事务驱动。

4.PROPAGATION_REQUIRES_NEW

创建一个新事务,如果存在当前事务,则挂起当前事务。类似于同名的EJB事务属性。

注意:实际事务挂起不会在所有事务管理器上开箱即用。这一点特别适用于JtaTransactionManager,它需要TransactionManager的支持。

PROPAGATION_REQUIRES_NEW范围总是定义自己的事务同步。现有同步将被挂起并适当地恢复。

5.PROPAGATION_NOT_SUPPORTED

不支持当前事务,存在事务挂起当前事务;始终以非事务方式执行。类似于同名的EJB事务属性。

注意:实际事务挂起不会在所有事务管理器上开箱即用。这一点特别适用于JtaTransactionManager,它需要TransactionManager的支持。

事务同步在PROPAGATION_NOT_SUPPORTED范围内是不可用的。现有同步将被挂起并适当地恢复。

6.PROPAGATION_NEVER

不支持当前事务;如果当前事务存在,抛出异常。类似于同名的EJB事务属性。

注意:事务同步在PROPAGATION_NEVER范围内不可用。

7.PROPAGATION_NESTED

如果当前事务存在,则在嵌套事务中执行,如果当前没有事务,类似PROPAGATION_REQUIRED(创建一个新的)。EJB中没有类似的功能。

注意:实际创建嵌套事务只对特定的事务管理器有效。开箱即用,这只适用于 DataSourceTransactionManager(JDBC 3.0驱动)。一些JTA提供者也可能支持嵌套事务。

注意:NESTED和REQUIRES_NEW区别?
1.回滚:
NESTED在创建内层事务之前创建一个保存点,内层事务回滚只回滚到保存点,不会影响外层事务(真的可以自动实现吗?)。外层事务回滚则会连着内层事务一起回滚;
REQUIRES_NEW构造一个新事务,和外层事务是两个独立的事务,互不影响。

2.提交:NESTED是嵌套事务,是外层事务的子事务。外层事务commit则内部事务一起提交,只有一次commit;REQUIRES_NEW是新事务,完全独立的事务,独立进行2次commit。

注:
NESTED嵌套事务能够自己回滚到保存点,但是嵌套事务方法中的上抛的异常,外部方法也能捕获,那么外部事务也就回滚了,所以如果期望实现内部嵌套异常回滚不影响外部事务,那么需要捕获嵌套事务的异常,并保证吃掉异常,不再上抛。

四、总结

本节讲解了事务的4大特性和6大属性的概念。

注意:JtaTransactionManager的类注释上说:Transaction suspension (REQUIRES_NEW, NOT_SUPPORTED) is just available with a JTA TransactionManager being registered." 这是片面的,只是说JTA TransactionManager支持挂起,并没有说DataSourceTransactionManager不支持。经过第四节实测,发现完全是支持的。网上很多说REQUIRES_NEW、NOT_SUPPORTED必须要JTA TransactionManager才行的完全是错误的说法。

不同传播机制 事务名称 描述 事务管理器要求 是否支持事务 是否开启新事务 回滚规则

REQUIRED

要求

存在加入,不存在创建新

不一定

存在一个事务:1.外部有事务加入,异常回滚;2.外部没事务创建新事务,异常回滚

SUPPORTS

支持

存在加入,不存在非事务

最多只存在一个事务: 1.外部有事务加入,异常回滚;2.外部没事务,内部非事务,异常不回滚

MANDATORY

强制

存在加入,不存在抛异常

最多只存在一个事务: 1.外部存在事务加入,异常回滚;2.外部不存在事务,异常无法回滚

REQUIRES_NEW

要求新

存在挂起创建新,不存在创建新

可能存在1-2个事务:1.外部存在事务挂起,创建新,异常回滚自己的事务 2.外部不存在事务,创建新, 异常只回滚新事务

NOT_SUPPORTED

不支持

存在挂起,不存在非事务

最多只存在一个事务:1. 外部有事务挂起,外部异常回滚;内部非事务,异常不回滚2.外部无事务,内部非事务,异常不回滚

NEVER

坚决不

存在抛异常

最多只存在一个事务:1.外部有事务,外部异常回滚;内部非事务不回滚 2.外部非事务,内部非事务,异常不回滚

NESTED

嵌套

存在嵌套,不存在创建新

DataSourceTransactionManager

❎(同一个物理事务,保存点实现嵌套)

存在一个事务:1. 外部有事务,嵌套事务创建保存点,外部异常回滚全部事务;内部嵌套事务异常回滚到保存点;2.外部不存在事务,内部创建新事务,内部异常回滚

参考书籍《精通Spring4.x企业应用开发实战》

参考博文链接:https://www.cnblogs.com/dennyzhangdd/p/9549535.html

spring事务详解(一)初探讨的更多相关文章

  1. spring事务详解(五)总结提高

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.概念 ...

  2. spring事务详解(四)测试验证

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  3. spring事务详解(二)简单样例

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  4. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  5. spring事务详解(一)初探事务

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...

  6. Spring、Spring事务详解;使用XML配置事务

    @Transactional可以设置以下参数: @Transactional(readOnly=false) // 指定事务是否只读的 true/false @Transactional(rollba ...

  7. spring事务详解(转载+高亮)

    spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...

  8. spring事务详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt122 Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式 ...

  9. JAVA框架之Spring【Spring事务详解】

    spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...

  10. spring事务详解(二)实例

    在Spring中,事务有两种实现方式: 编程式事务管理: 编程式事务管理使用底层源码可实现更细粒度的事务控制.spring推荐使用TransactionTemplate,典型的模板模式. 申明式事务管 ...

随机推荐

  1. 《Linux内核》读书笔记 第十八章

  2. 第二个Spring冲刺周期团队进展报告

    第一天:找识别不了的原因 第二天:继续找识别不了的原因 第三天:找文字库,找到tessdata语言包,放到手机SD卡根目录 第四天:了解OCR引擎 第五天:将导入tess-two导入到项目中,并进行测 ...

  3. [BUG随想录] expat不兼容BUG

    本周五软工团队项目的第一次前后端全部对接时,出了一个蛋疼的错误. 最初起因是小丽叔出于安全的考虑,使用守护进程来跑Web服务器.守护进程(Daemon)是运行在后台的一种特殊进程,如果服务器用root ...

  4. 05 方法与数组笔记【JAVA】

    ---恢复内容开始--- 1:方法(掌握) (1)方法:就是完成特定功能的代码块. 注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法. (2)格式: 修饰符 返回值类型 方法名(参数类 ...

  5. VS2013快速安装教程

    1.下载vs2013安装镜像.VS2013_RTM_ULT_CHS.iso链接: http://pan.baidu.com/s/1mguOdiK密码: rllz  建议使用百度网盘客户端下载,虽然被人 ...

  6. 【壹拾壹周】final用户调查

    组名: 新蜂组长: 武志远组员: 宫成荣 谢孝淼 杨柳 李峤项目名称:java俄罗斯方块NEO 问卷星由宫成荣同学发布: 温馨提示:点击右键,在新标签中打开图片,单击图片即可放大.或者使用按住ctrl ...

  7. idea的激活

    参考网址:https://blog.csdn.net/qq_34273222/article/details/78810799 侵删 1.进到文件夹中:C:\Windows\System32\driv ...

  8. oracle12c ORA-28040: No matching authentication protocol

    出错原因:11G客户端连12C数据库服务端会报这个错 解决方案一:CSDN优质解决方案,大家都说可以,然而我这边操作了不行 转自13楼:http://bbs.csdn.net/topics/39066 ...

  9. emWin 工程之汉字显示

    @2018-7-10  工程加入字库后,液晶屏显示非法文字,无法正确显示设置的文字 解决办法 将显示汉字的文件 <MainTask.c> 修改为 UTF-8 格式后显示正常,修改为 ANS ...

  10. bzoj5164: 餐厅计划问题(三分+贪心)

    网络流经典题里餐巾计划的加强版...天数变成了$10^5$,那就不能用费用流做了... 考虑费用流的时候,单位费用随流量的增加而减少,也就是说费用其实是个单峰(下凸)函数. 那么可以三分要买的餐巾个数 ...