Mysql的事务

一、事务的ACID特性

1、原子性(atomicity)

原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚

2、一致性(consistency)

一致性是指事务执行前后,数据从一个 合法性状态 变换到另外一个 合法性状态

举例:

同一事务下,账户转账,A账户减200,B账户就要加200,符合预期的才是一致性

3、隔离型(isolation)

事务的隔离性是指一个事务的执行 不能被其他事务干扰 ,即一个事务内部的操作及使用的数据对 并发 的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

举例:

A事务和B事务各自执行,互不影响。

4、持久性(durability)

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

二、隔离性引起的并发问题

1、脏写( Dirty Write

一个事务写了没提交,另外一个接着写了

对于两个事务 Session ASession B,如果事务Session A 修改了 另一个 未提交 事务Session B 修改过 的数据,那就意味着发生了 脏写

举例:

账户余额为100,B事务增加了100,但是事务未提交,A事务在B的基础上将余额减少了100,如果B事务回滚就会引起数据错乱,这种现象就是脏写。

2、脏读( Dirty Read

一个事务写了没提交,另外一个接着读了(读未提交:读到了一个事务未提交的内容)

对于两个事务 Session ASession B,Session A 读取 了已经被 Session B 更新 但还 没有被提交 的字段。之后若 Session B 回滚 ,Session A 读取 的内容就是 临时且无效

举例:

账户余额为100,B事务增加了100,但是事务未提交,A事务读取到的账户金额是200,然后在200基础上执行后续操作,如果B事务回滚就会引起数据错乱,这种现象就是脏读。

3、不可重复读( Non-Repeatable Read

一个事务读取了一条数据,另一个事务更新了该条数据,之前那个事务再读的话,数据就变了

注意:不可重复读是针对同一条数据出现了前后不一致的现象

对于两个事务Session ASession B,Session A 读取 了一个结果,然后 Session B 更新 了该数据。 之后Session A 再次读取 同一个数据, 结果就不同 了。那就意味着发生了不可重复读。

举例:

账户余额为100,A事务第一次读取到的账户金额是100,B事务增加了100,A事务再次读取变成了200,A事务发生了不可重复读现象。

4、幻读( Phantom

一个事务第一次读取表中没有数据,此时另外一个事务增加了一条数据,之前事务再次读取发现多了一条数据

注意:幻读是针对整个表的数据,出现了读取前后不一致的现象

对于两个事务Session ASession B, Session A 从一个表中 读取 了数据, 然后 Session B 在该表中 插入 了一些新的行。 之后, 如果 Session A 再次读取 同一个表, 就会多出几行。那就意味着发生了幻读。

三、SQL中的四种隔离级别

  • READ UNCOMMITTED :读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。

  • READ COMMITTED :读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。

  • REPEATABLE READ :可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别

  • SERIALIZABLE :可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。

如何解决幻读?

解决幻读的方式有很多,但是它们的核心思想就是一个事务在操作某张表数据的时候,另外一个事务不允许新增或者删除这张表中的数据了。解决幻读的方式主要有以下几种:

  • 将事务隔离级别调整为 SERIALIZABLE

  • 在可重复读的事务级别下,给事务操作的这张表添加表锁。

  • 在可重复读的事务级别下,给事务操作的这张表添加 Next-key Lock(Record Lock+Gap Lock)

如何设置事务的隔离级别?

SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'

#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE