MySQL事务特性以及事务的隔离级别

事务的四大特性(ACID)

  数据库支持事务操作,必须要具备以下四个特性:

  1. 原子性(Atomicity)
      原子性:事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  2. 一致性(Consistency)
      一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态,即一个事务执行之前和执行之后都必须处于一致性状态。例如转账,A和B两者的钱加起来一共是5000,则不管A和B之间如何转账,转几次账,事务结束后两者的金额相加起来应该是5000,即事务的一致性。
  3. 隔离性(Isolation)
      隔离性:当多个用户并发访问数据库时,如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务S1和S2,在事务S1看来,S2要么在S1开始之前就已经结束,要么在S1结束之后才开始,即每个事务都感觉不到有其他事务在并发地执行。
  4. 持久性(Durability)
      持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的隔离级别

  数据库事务:读取事务(SELECT)、修改事务(UPDATE/INSERT)。在没有事务隔离的时候,多个事务在同一时刻对同一数据的操作可能会影响到最终期望的结果,通常有四种情况:

  1. 两个更新事务同时修改一条数据时,会造成更新的丢失
  2. 一个更新事务更新一条数据时,另一个读取事务读取了还没提交的更新,会出现读取到脏数据
  3. 一个读取事务读取一条数据时,另一个更新事务修改了这条数据,会出现不可重现的读取
  4. 一个读取事务读取时,另一个插入事务插入了一条新数据,可能多读出一条数据,出现幻读

可总结为:

  • 修改时允许修改(丢失更新)
  • 修改时允许读取(脏读)
  • 读取时允许修改(不可重复读)
  • 读取时允许插入(幻读)

脏读
  脏读:在一个事务处理过程里读取了另一个未提交的事务中的数据。
  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元

update account set money=money+100 where name=B; //此时A通知B
update account set money=money-100 where name=A;

当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

不可重复读
  不可重复读:在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。例如事务S1在读取某一数据,而事务S2立马修改了这个数据并且提交事务给数据库,事务S1再次读取该数据就得到了不同的结果,发送了不可重复读。
  不可重复读和脏读的区别:脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

幻读
  幻读是事务非独立执行时发生的一种现象。事务S1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务S2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务S1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是事务S2中添加的,就好像产生幻觉一样,即幻读。
  幻读和不可重复读都是读取了另一条已经提交的事务,所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体。

MySQL数据库的四种事务隔离级别

  • Read Uncommitted(读取未提交内容)
      所有事务都可以看到其他未提交事务的执行结果。读取未提交的数据,即脏读

  • Read Committed(读取提交内容)
      满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果

  • Repeatable Read(可重读)
      MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。但理论上会导致另一个棘手的问题:幻读 (Phantom Read)。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决该问题

  • Serializable(可串行化)
      最高的隔离级别,通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

在MySQL中,实现了这四种隔离级别,分别可能产生如下问题:
  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
  ③ Read committed (读已提交):可避免脏读的发生。
  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
  如果是使用JDBC对数据库的事务设置隔离级别的话,应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:
在这里插入图片描述
在JDBC中设置隔离级别的部分代码:

Connection conn=null;
Statement st=null;
ResultSet rs=null;
try{
	conn=JdbcUtils.getConnection();
	conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);//设置该链接的隔离级别,设置数据库的隔离级别一定要是在开启事务之前
	conn.setAutoCommit(false);//开启事务
}

  隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。

发布了107 篇原创文章 · 获赞 19 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/ThreeAspects/article/details/104114394
今日推荐