wangjie_fourth

may the force be with you

0%

MySQL的事务

MySQL事务的实现是在引擎级别上的,现在InnoDB存储引擎是支持事务的

事务的ACID

事务拥有四个重要的特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability

原子性Atomicity

事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样
注:MySQL使用undo log来保证事务的原子性

一致性Consistency

指事务将数据库从一种状态转变为另一种一致的的状态。事务开始前和结束后,数据库的完整性约束没有被破坏。例如工号带有唯一属性,如果经过一个修改工号的事务后,工号变的非唯一了,则表明一致性遭到了破坏。

可以理解成满足数据库完整性约束

隔离性Isolation

要求每个读写事务的对象对其他事务的操作对象能互相分离,即该事务提交前对其他事务不可见。 也可以理解为多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。例如一个用户在更新自己的个人信息的同时,是不能看到系统管理员也在更新该用户的个人信息(此时更新事务还未提交)。
注:MySQL通过MVVC + 锁机制来保证事务的隔离性。

持久性Durability

事务一旦提交,则其结果就是永久性的。即使发生宕机的故障,数据库也能将数据恢复,也就是说事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。这只是从事务本身的角度来保证,排除 RDBMS(关系型数据库管理系统,例如 Oracle、MySQL 等)本身发生的故障。
注:MySQL使用redo log来保证事务的持久性

事务的四种隔离级别

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
未提交读(Read uncommitted) 可能 可能 可能 不可能
已提交读(Read committed) 不可能 可能 可能 不可能
可重复读(Repeatable read) 不可能 不可能 可能 不可能
可串行化(Serializable) 不可能 不可能 不可能 可能

未提交读(Read uncommitted)

未提交读是指一个事务可以读取另一个事务还未提交的数据。这样就会产生脏读、也不能重复、也会产生幻读。即:

事务A 事务B
设置事务隔离级别为READ UNCOMMITTED 设置事务隔离级别为READ UNCOMMITTED
开始事务A:begin;
insert into test values (2);
select * from test;
开始事务A:begin;
select * from test;// 读取到2

已提交读(Read committed)

已提交读是指一个事务只能读取到另一个事务提交过后的数据。但是不可以重复读、也会产生幻读。即:

事务A 事务B
设置事务隔离级别为READ COMMITTED 设置事务隔离级别为READ COMMITTED
开始事务A:begin;
insert into test values (4, ‘Leon’);
开始事务B:begin;
查询数据:select * from test; (看不到id = 4的数据)
事务 A 提交: commit;
再次查询数据:select * from test; (id = 4的数据可见)
事务 B提交:commit;

可重复读(Repeatable read):MySQL的默认事务隔离级别

可重复读是指在同一事务中多次读取同样记录的结果是一致的。但这有可能产生幻读问题。

幻读指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新记录,当之前的事务再次读取时该范围的记录会产生幻行。比如说:
事务A查询范围为1~10的数据,此时表里只有1~9的数据;而事务B也开始准备事务查询,自然是只能看到1~9的数据;当事务A插入id为10的数据,并提交事务后;事务B还是看不到id=10的数据,此时事务B如果尝试插入id=10的数据就有可能报错。

事务A 事务B
设置事务隔离级别为REPEATABLE READ 设置事务隔离级别为REPEATABLE READ
开始事务A:begin;
查询:select * from test;
开始事务B:begin;
查询数据:select * from test; (看不到id = 10的数据)
insert into test(id,username) values(10,’zhangsan’);
事务 A 提交: commit;
再次查询数据:select * from test; (看不到id = 10的数据)

MySQL的InnoDB是如何解决幻读问题

MySQL使用next-key lock + MVVC解决幻读问题:https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html

可串行化(Serializable)

可串行化是指事务与其他事务是串行执行的,避免了幻读问题。

事务A 事务B
设置事务隔离级别为SERIALIZABLE 设置事务隔离级别为SERIALIZABLE
开始事务A:begin;
insert into test(id, usename) values(15, ‘LaoZhang’);
开始事务B:begin;
查询数据:select * from test; (看不到任何数据,一直等待)
事务 A 提交: commit; 立即返回数据

相关命令


https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html