mysql(二) mysql事务概念,隔离级别,传播特性

(一)什么是事务:

   事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
   特性:事务是恢复和并发控制的基本单位。
   事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务,即使不能都很好的满足,也要考虑支持到什么程度。

(二)ACID:

   ACID 理论是对事务特性的抽象和总结,方便我们实现事务。你可以理解成:如果实现了操作的 ACID 特性,那么就实现了事务。ACID的具体含义详述如下。

原子性(Atomicity):原子性是指单个事务本身涉及到的数据库操作,要么全部成功,要么全部失败,不存在完成事务中一部分操作的可能。以上文说的转账为例,就是要么操作全部成功,A的钱少了,B的钱多了;要么就是全部失败,AB保持和原来一直的数目。
mysql(二) mysql事务概念,隔离级别,传播特性_第1张图片
一致性(Consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态,事务的中间状态不能被观察到的。还是以转账为例,原来AB账户的钱加一起是1000,相互转账完成时候彼此还是1000,所以一致性理解起来就是事务执行前后的数据状态是稳定的,对于转账就是金额稳定不变,对于其他的事务操作就是事务执行完成之后,数据库的状态是正确的,没有脏数据。

隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。隔离性侧重于多个事务之间的特性,也就是说多个事务之间是没有相互影响的比如A给B转账和B给C转账这两个事务是没有影响的(这里B给C转账如果和A给B转账的事务同时进行的时候,B的金额正确性问题保证就要看隔离级别了)。

持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

(三)事务的隔离级别:

   在多个事务并发操作数据库(多线程、网络并发等)的时候,如果没有有效的避免机制,就会出现脏读、不可重复读和幻读这3种问题。

脏读(Dirty Read):

A事务读取B事务尚未提交的数据,此时如果B事务由于某些原因执行了回滚(commit后是不能rollback的)操作,那么A事务读取到的数据就是脏数据(没有第二次读取,还是读取的B事务没有rollback前的数据)。

参考下图,事务A读取到了事务B未提交的记录。
mysql(二) mysql事务概念,隔离级别,传播特性_第2张图片
不可重复读(Nonrepeatable Read):

一个事务内前后多次读取,数据内容不一致。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的(A第一次读取B未修改的数据,第二次读取时B已经修改)。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

参考下图,事务A读取到的name可能为“张三”,也可能为“李四”。
mysql(二) mysql事务概念,隔离级别,传播特性_第3张图片

幻读(Phantom Read):

一个事务内前后多次读取,数据总量不一致。参考下图,事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。
mysql(二) mysql事务概念,隔离级别,传播特性_第4张图片

   不可重复读和幻读有些相似,两者的区别在于:不可重复读的重点在于修改,同样的条件, 你读取过的数据,再次读取出来发现值不一样了;而幻读的重点在于新增或者删除(参考MySQL官网https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html对幻读的定义,记录的减少也应该算是幻读),同样的条件, 第 1 次和第 2 次读出来的记录数不一样。

隔离级别:

   事务的隔离性是指多个并发的事务同时访问一个数据库时,一个事务不应该被另一个事务所干扰,每个并发的事务间要相互进行隔离。SQL 标准定义了以下四种隔离级别:

  • 读未提交(Read Uncommitted):一个事务可以读取到另一个事务未提交的修改。这种隔离级别是最弱的,可能会产生脏读,幻读,不可重复读的问题。
  • 读已提交(Read Committed):一个事务只能读取另一个事务已经提交的修改。其避免了脏读,仍然存在不可以重复读和幻读的问题。SQL Server和Oracle的默认隔离级别就是这个。
  • 重复读(Repeated Read):同一个事务中多次读取相同的数据返回的结果是一样的。其避免了脏读和不可重复读问题,但是幻读依然存在。MySQL中的默认隔离级别就是这个,不过MySQL通过多版本并发控制(MVCC)、Next-key
    Lock等技术解决了幻读问题。
  • 串行化(Serializable):这是数据库最高的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。在这种级别下,脏读、不可重复读、幻读都可以被避免,但是执行效率奇差,性能开销也最大。

事务的隔离级别和脏读、不可重复读、幻读的关系总结如下表所示:
mysql(二) mysql事务概念,隔离级别,传播特性_第5张图片

(四)事务的传播特性:

   在项目开发中,一般将事务设置在service层,当调用这个service方法时,这个service保证了所有的操作在同一个事务中,所有对数据库的操作要么一起成功,要么一起失败。
如果service方法除了调用DAO,还调用了其他的service方法,如何通过事务控制,保证数据的一致,这个时候就需要事务的传播特性。

事务的传播特性共有7种:

   PROPAGATION_REQUIRED:支持当前事务,如果不存在就新建一个(默认) ;

   PROPAGATION_REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起;

   PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

   PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务;

   PROPAGATION_MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常;

   PROPAGATION_NEVER:以非事务方式运行,如果有事务存在,抛出异常;

   PROPAGATION_NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。

作用:

   传播特性主要控制是使用老的事务,还是创建新的事务,或者事务是否运行在上下文中。

java使用举例:

@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
    。。。。
}

xml配置举例:



	
		
		
		
		
		
	

 

	
  

你可能感兴趣的:(mysql,java)