数据库事务详解

事务概念

事务在数据库里是很重要的概念,指的是用户定义的一组不可分割的数据库操作序列,这组操作要么全执行,要么全失败回滚,保证了数据操作前后持一致性。以 JDBC 操作数据库中的转账汇款为例,在没开启事务的情况下,假设 xm、xh各有 1000 块钱,总共 2000 块钱,当 xm 向 xh 汇款 100 块钱时,执行如下图的方法:

事务概念

xm 账户先是减去了相应的 100 ,但是由于 /by zero 异常,xh 账户上却没有加上相应的 100,此时就是丢掉了数据前后的一致性,因为当上图 transfer 方法执行后,xm 还有 900,xh 还是 1000 块钱,总共 1900 块钱,与刚开始 xm、xh 共持有的钱 2000 不符,也就是 xm 平白无故的就消失了 100 块钱,这个要是在现实生活中换做谁都是接收不了的。

而事务开启后,上图中这两条 SQL 语句将会变成一荣俱荣,一损俱损的状态(原子性),只要事务还没提交,即使发生了 /by zero 错误,xm 减去 100 的那条 SQL 语句就会被回滚,xm 最终还是 1000 块钱,从而保证了 xm、xh 所持有总钱数的一致性。

四大特性(ACID)

  • 原子性(Atomicity):用户定义的多条 SQL 语句是一个整体,要么全部执行,要么全部不执行。
  • 一致性(Consistency):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态,就像上面说的转完钱后 xm、xh 持有的总钱数应保持不变。
  • 隔离性(Isolation):多个事务并发访问数据时,事务之间是相互隔离的,相互之间不会存在影响。数据库设立了不同的隔离级别,MySQL 有四个隔离级别:Read uncommittedRead committedRepeatable read(默认)、Serializable,详细后面分析。
  • 持久性(Durability):只要事务提交,数据就会被保存至数据库并保证永不丢失。也就是从内存里保存到了磁盘里,即使是数据库宕机崩溃、断电,数据都不会丢失。

事务并发问题

当多个事务并发访问数据时,若不对并发操作加以控制的话,就可能会造成查询和更新到不正确的数据,破坏事务前后的一致性,发生脏读不可重复读虚读

  • 脏读(dirty read):一个事务读取到了另一个事务未提交时修改的数据。解析图如下:

事务并发问题

事务 B 先查询了 xm 的 money,接着事务 A 修改了 xm 的 money,A 并没有提交事务,事务 B 再次查询 xm 的 money 时就变为了事务 A 修改后的内容了,这个就是脏读。

  • 不可重复读(unrepeatable read):一个事务读取到了另一个事务提交后的数据。解析图如下:

事务并发问题

意思是指:事务 A 在 update 一行数据的时候,事务 B 在其 update 前后都访问了这行数据,导致事务 B 两次查询这行数据时结果不一致。注:这里是指 update 一行数据,与幻读中的 insert 数据不同。

  • 幻读/虚读(phantom read):一个事务读取到了另一个事务提交后的数据,解析图如下:

事务并发问题

这个和不可重复读的概念很像,在事务 B insert 一行数据时,事务 A 在 insert 之前查了两次表中所有数据,导致两次结果集不一致,第二次查询时多了一条事务 B insert 的数据。注:这里是指 insert 一行数据,与幻读中的 update 数据不同。

  • 丢失更新(lost update)

事务并发问题

事务并发问题

MySQL 事务隔离级别

事务隔离级别是事务并发控制的整体解决方案,它通过锁机制来实现。MySQL 有四个隔离级别,通过设置相应隔离级别可以防止脏读、不可重复读、幻读。

  • Read uncommitted(读未提交):可以读取未提交的记录,会出现脏读、幻读、不可重复读,所有并发问题都可能遇到。
  • Read committed(读已提交):事务中只能读到已提交的修改,不会出现脏读现象,但是会出现幻读、不可重复读。
  • Repeatable read(可重复读):解决了不可重复读问题,但是仍然存在幻读问题,MySQL InnoDb 默认的隔离级别。
  • Serializable(序列化):最强级别的事务隔离,解决脏读、不可重复读、幻读问题,但是开启后会拖慢数据库并发效率,性能最低。

查看隔离级别:

1
SELECT @@session.tx_isolation, @@global.tx_isolation;

session / local 为会话变量,global 为全局变量。

设置隔离级别:

1
SET @@session.tx_isolation = 0/1/2/3;

0~3 分别表示:Read uncommitted、Read committed、Repeatable read、Serializable