① Atomi(原子性):事务中包含的操做被看作一个整,要么彻底部成功,要么所有失败。数据库
② Consistency(一致性):事务在完成时,必须是全部的数据都保持一致状态,保证了数据的完整性和一致性。并发
③ Isolation(隔离性):当多个用户并发访问数据库时,好比操做同一张表时,数据库为每个用户开启的事务,不能被其余事务的操做所干扰,多个并发事务之间要相互隔离。.net
这里的隔离性就是下面咱们要说的隔离级别,为了减小事务在修改数据上的相互影响。blog
④ Durability(持久性):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即使数据库系统遇到故障也不会丢失提交事务的操做。事务
事务传播行为(propagation behavior)指的就是当一个事务方法A被另外一个事务方法B调用时,这个事务方法A应该如何进行。换句话说,须要发生方法件的调用,才会存在传播行为,对于单个事务方法而已,没有传播的概念。ci
传播行为 | 含义 | 应用场景 |
---|---|---|
REQUIRED | 默认传播行为,当前上下文不存在事务,因此会开启一个新的事务,当上下文存在事务,则融入当前事务(它是个机会主义者,既能够暗度陈仓,也能够独当一面) | 大部分简单场景 |
SUPPORTS | 若是存在一个事务,支持当前事务。若是没有事务,则非事务的执行(它是个保守派,随波逐流,从不另起炉灶) | 查询 |
MANDATORY | 若是存在一个事务,支持当前事务。若是没有一个活动的事务,则抛出异常(它是个独裁者,只许州官放火,不准百姓点灯) | |
REQUIRES_NEW | 它会开启一个新的事务。若是一个事务已经存在,则先将这个存在的事务挂起。(它是个革新派,开天辟地) | 批量操做时,须要对单调数据进行控制 |
NOT_SUPPORTED | 老是非事务地执行,并挂起任何存在的事务(他是个悲观主义者,不主动,谁来都拒绝) | |
NEVER | 老是非事务地执行,若是存在一个活动事务,则抛出异常(怎么说,这个有点反人类) | |
NESTED | 嵌套事务一个很是重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所作的动做。而内层事务操做失败并不会引发外层事务的回滚。(害,活像一个爱情弱势方,受害者,左右不了对方,被对方左右) |
准确来讲,事务的隔离级别只有四个,分别为:资源
单单看这几个字有点干,其余的先无论,先来看一下他们都能解决啥问题,以及没法解决什么问题先get
异常现象 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | √ | √ | √ |
读写提交 | × | √ | √ |
可重复读 | × | × | √ |
串行化 | × | × | × |
如何理解上面这个表格呢?首先,若是是简单的查询,那是不存在的什么问题的,由于你只进行了查询而已。那么若是你有对数据库的更新修改操做,是否是就会产生问题呢?不必定,若是这个时间内只有一个事务,那你作再多的操做,都是不会有问题的,要么这个事务的操做所有成功,要么所有失败。因此在对事务产生问题的讨论上,都是针对并发事务。这一点与事务的传播性的特色同样。简单的理解,就是同一时间,对同一数据有多个事务在操做。it
那咱们都知道,每个事务的里的操做,都会被计算机分割成不少的原子操做,由cpu进行调度执行,因此就涉及这些操做的一个排列问题,但咱们知道cpu的调度是随机的,因此的就会产生不少可能性。这些操做的执行顺序,致使了面临一些问题。io
最低级别读未提交(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 | 最严格的级别,事务串行执行,资源消耗最大 |
事务在读数据的时候并未对数据加锁。
务在修改数据的时候只对数据增长行级共享锁。
事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,当即释放该行级共享锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。