谈谈Java事务
事务具基本特征(ACID)
① Atomi(原子性):事务中包含的操作被看做一个整,要么完全部成功,要么全部失败。
② Consistency(一致性):事务在完成时,必须是所有的数据都保持一致状态,保证了数据的完整性和一致性。
③ Isolation(隔离性):当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
这里的隔离性就是下面我们要说的隔离级别,为了减少事务在修改数据上的相互影响。
④ Durability(持久性):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便数据库系统遇到故障也不会丢失提交事务的操作。
事务的传播行为
事务传播行为(propagation behavior)指的就是当一个事务方法A被另一个事务方法B调用时,这个事务方法A应该如何进行。换句话说,需要发生方法件的调用,才会存在传播行为,对于单个事务方法而已,没有传播的概念。
传播行为 | 含义 | 应用场景 |
---|---|---|
REQUIRED | 默认传播行为,当前上下文不存在事务,所以会开启一个新的事务,当上下文存在事务,则融入当前事务(它是个机会主义者,既可以暗度陈仓,也可以独当一面) | 大部分简单场景 |
SUPPORTS | 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行(它是个保守派,随波逐流,从不另起炉灶) | 查询 |
MANDATORY | 如果存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常(它是个独裁者,只许州官放火,不许百姓点灯) | |
REQUIRES_NEW | 它会开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起。(它是个革新派,开天辟地) | 批量操作时,需要对单调数据进行控制 |
NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务(他是个悲观主义者,不主动,谁来都拒绝) | |
NEVER | 总是非事务地执行,如果存在一个活动事务,则抛出异常(怎么说,这个有点反人类) | |
NESTED | 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。(害,活像一个爱情弱势方,受害者,左右不了对方,被对方左右) |
事务的隔离级别
准确来说,事务的隔离级别只有四个,分别为:
- 读未提交(READ_UNCOMMITTED)
- 读已提交(READ_COMMITTED)
- 可重复读(REPEATABLE_READ)
- 串行化(SERIALIZABLE)
单单看这几个字有点干,其他的先不管,先来看一下他们都能解决啥问题,以及无法解决什么问题先
异常现象 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | √ | √ | √ |
读写提交 | × | √ | √ |
可重复读 | × | × | √ |
串行化 | × | × | × |
如何理解上面这个表格呢?首先,如果是简单的查询,那是不存在的什么问题的,因为你只进行了查询而已。那么如果你有对数据库的更新修改操作,是不是就会产生问题呢?不一定,如果这个时间内只有一个事务,那你做再多的操作,都是不会有问题的,要么这个事务的操作全部成功,要么全部失败。所以在对事务产生问题的讨论上,都是针对并发事务。这一点与事务的传播性的特点一样。简单的理解,就是同一时间,对同一数据有多个事务在操作。
那我们都知道,每一个事务的里的操作,都会被计算机分割成很多的原子操作,由cpu进行调度执行,所以就涉及这些操作的一个排列问题,但我们知道cpu的调度是随机的,所以的就会产生很多可能性。这些操作的执行顺序,导致了面临一些问题。
最低级别读未提交(READ_UNCOMMITTED),什么问题都有可能发生,不适合并发事务场景
由上面所提到的事务的持久性可以得知,事务的持久化,是建立在事务被提交的基础上的。也就是说,事务A没提交,对数据的操作都不算真正的生效,那么如果在未提交前,被别的事务B的读取到这部分数据,那么你最终提交的化还好,严格来说不算脏数据,但假如事务A回滚了,那读的这部分数据其实是错误的,我们把它称之为“脏数据”,这是并发事务面临的第一个问题。
要解决“脏数据”问题,就必须保证一个事务不会读到另一个并行事务已修改但未提交的数据,这正是读已提交(READ_COMMITTED)隔离级别所要求的。换句话说就是“我修改的数据还没提交你不能读”。解决了脏数据问题后。我读到的数据的确都是“生效”的了。
但这会带来一个问题,单事务A需要对一个数据多次读取的时候,中间可能存在一个可能:事务B修改这个数据了,由该级别读到的数据是已提交可知,事务B对数据的修改操作肯定是生效的了,所以事务A多次读到的结果可能不一致,这就是“不可重复读”问题。
要解决“不可重复读”问题,很显然,我就得加强约束,上一级是我修改的数据还没提交你不能读,这次是当我读数据开始,到我所在的事务还没提交之前,你不能读,这意味着不管事务A读数据后有多少操作,并发事务B都得等待,可以看到的“锁住”的范围更大了,也相应带来更大的损耗。此时解决重复读的问题,级别是可重复读(REPEATABLE_READ)
但可重复读级别解决的是同一竞争数据的重复读问题,假如事务A多次通过特定条件多次读取m条数据,有事务C,插入n条数据服务事务A查询条件,或者修改了其他t条数据同样符合事务A的条件,那事务A后面读取可能就是m+n或m+t条数据了,此为”幻读“现象,要解决此问题
要解决幻读现象,只能祭出最后杀招,串行化(SERIALIZABLE)级别
总结如下
隔离等级 | 含义 |
---|---|
READ_UNCOMMITTED | 最低等级,从上表可以看到,啥问题解决不了,所以当并发事务操作同一数据时,啥情况都可能发生,所以一般不用于并发事务场景 |
READ_COMMITTED | 保证了一个事务不会读到另一个并行事务已修改但未提交的数据 |
REPEATABLE_READ | 保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据 |
SERIALIZABLE | 最严格的级别,事务串行执行,资源消耗最大 |
数据库实现
未提交读的数据库锁情况(实现原理)
事务在读数据的时候并未对数据加锁。
务在修改数据的时候只对数据增加行级共享锁。
提交读的数据库锁情况
事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
可重复读的数据库锁情况
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
可序列化的数据库锁情况
事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。
参考资料
谈谈Java事务的更多相关文章
- 转!!java事务的处理
java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务.如果数据库操作在某一步没有执行或出现异常而导致事务失败,这样有的事务被执行有的就没有被执行,从而就有了事务的回滚,取消先前 ...
- 谈谈Java程序员进阶的那些知识和方向
谈谈Java程序员进阶的那些知识和方向 记得前段时间看过一篇文章谈到一种程序员叫野生程序员,战斗力极强,可以搞定一切问题,但是通常看问题抓不到本质,或者说是google/baidu/stackover ...
- 老鸟谈谈JAVA EE的学习
老鸟谈谈JAVA EE的学习 因为出差和项目的原因,有将近一个月的时间没有更新博客了,今天终于得闲,和兄弟们分享一下JAVA EE的学习心得.书中带过,直入主题,下面我们首先看看什么是JAVA EE. ...
- 深入Java事务的原理与应用
一.什么是JAVA事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 ( ...
- 谈谈Java的集合组件
让我们一起谈谈Java的集合组件 我们在使用Java的时候,都会遇到并使用到Java的集合.在这里通过自己的理解和网上的资源对Java的集合方面的使用做一个简单的讲解和总结. Java主要分为3个集合 ...
- java事务的类型——面试被问到
Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务. 1.JDBC事务 JDBC 事务是用 Connection 对象控制的.JDBC Conne ...
- java事务管理
一.什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isol ...
- java事务的处理
java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务. 如果数据库操作在某一步没有执行或出现异常而导致事务失败,这样有的事务被执行有的就没有被执行,从而就有了事务的回滚,取消先 ...
- 谈谈java的BlockingQueue
http://www.cnblogs.com/archy_yu/archive/2013/04/19/3018479.html 博客园 首页 新随笔 联系 管理 随笔- 92 文章- 0 评论- ...
随机推荐
- macOS Big Sur 11.4 (20F71) 正式版(DMG、ISO、IPSW),百度网盘下载
本站提供的 macOS Big Sur 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装. 请访问原文链接:https://sy ...
- 七、.net core(.NET 6)使用Serilog进行配置和实现日志记录
使用Serilog来实现日志记录 先安装Serilog六件套神装包: 也可以对个别相应的包进行删除等,都是可以的.例如,标注的1是读取配置文件的,如果不需要通过配置文件进行操作,就可以使用这个包.2是 ...
- Redis(二) 数据类型操作指令以及对应的RedisTemplate方法
1.Redis key值操作以及RedisTemplate对应的API 本文默认使用RedisTemplate,关于RedisTemplate和StringRedisTemplate的区别如下 Red ...
- 新特性,推荐一款超强接口管理神器 Apifox
去年,在公众号给大家推荐了一款新面市不久的接口测试神器:Apifox,如果还未了解的读者,感兴趣的话可查阅原文:推荐一款技术人必备的接口测试神器:Apifox 为了照顾新进来的读者,且最近一年,Api ...
- adb基础命令
adb运行原理: 启动一个 adb 客户端时,此客户端首先检查是否有已运行的 adb 服务器进程.如果没有,它将启动服务器进程.当服务器启动时,它与本地 TCP 端口 5037 绑定,并侦听从 adb ...
- 【VBA】列号与字母(列名)的相互转换 (自定义函数)
1. '列号转字母(列名) Function Num2Name(ByVal ColumnNum As Long) As String On Error Resume Next Num2Name = & ...
- SpringBoot和Spring到底有没有本质的不同?
现在的Spring相关开发都是基于SpringBoot的.最后在打包时可以把所有依赖的jar包都打进去,构成一个独立的可执行的jar包.如下图: 使用java -jar命令就可以运行这个独立的jar包 ...
- 面试官:如何在分布式场景下生成全局唯一 ID?
在分布式系统中,有一些场景需要使用全局唯一 ID ,可以和业务场景有关,比如支付流水号,也可以和业务场景无关,比如分库分表后需要有一个全局唯一 ID,或者用作事务版本号.分布式链路追踪等等,好的全局唯 ...
- DFS————从普及到IOI(暴力骗分小能手)
DFS 啦啦啦,再来水一波 先说思想吧! 背景: 深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法. ----来自度娘 一.思想 DFS算法思 ...
- Android系统编程入门系列之应用初始化Application
在上一篇文章中我们了解到Android系统启动应用的时候,会首先加载AndroidManifest.xml清单文件中的一系列信息,在清单文件中如果不指定<application></ ...