【MySQL学习】2.事务和事务的隔离级别


1 什么是事务?

是数据库管理系统(DBMS)执行过程中的一个逻辑单位(不可再进行分割),由一个有限的数据库操作序列构成(多个DML语句,select语句不包含事务),要不全部成功,要不全部不成功

2 事务特性

2.1 原子性(atomicity)

一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败,对于一个事务来说,不能只执行其中的一部分操作。

2.2 一致性(consistency)

事务将数据库从一种一致性状态转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。

2.3 隔离性(isolation)

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

2.4 持久性(durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的修改数据也不会丢失。

3 事务并发引发的问题

3.1 脏读

当一个事务读取到了另外一个事务修改但未提交的数据。

T1T2
begin
select money from t1 where id=Kingbegin
update t1 set money=1500 where id=King
select money from t1 where id=King
rollback

上表中,事务 T2 修改了一行记录,但是没有提交。然后事务 T1 读取到了未提交的数据, 如果事务 T2 回滚其更改的数据或者再次更新,那么在事务 T1 中看到的记录可能就是错误的。事务 T1 读取到了 King 老师余额为 1500 的记录,但是事务 T2 执行了回滚操作,这时并不存在 King 老师余额为 1500 记录。

3.2 不可重复读

当事务内相同的记录被检索两次,且两次得到的结果不同时(强调修改)。

T1T2
begin
select money from t1 where id=Kingbegin
update t1 set money=1500 where id=King
commit;
select money from t1 where id=King
commit;

3.3 幻读(phantom read)

在事务执行过程中,另一个事务将新记录添加到正在读取的事务中时,会发生幻读(强调新增)。

T1T2
begin
select money from t1 where id=Kingbegin
insert into t1(id, money) values(King, 500);
commit;
select money from t1 where id=King
commit;

那如果事务 T2 中是删除了符合的记录而不是插入新记录,那事务T1中之后再根据条件读取的记录变少了,这种现象算不算幻读呢?

明确说一下,在MySQL中这种现象不属于幻读,幻读强调的是一个事务按照某个相同条件多次读取记录时,后读取时读到了之前没有读到的记录

那对于先前已经读到的记录,之后又读取不到这种情况,算啥呢?

其实这相当于对每一条记录都发生了不可重复读的现象。幻读只是重点强调了读取到了之前读取没有获取到的记录

4 隔离级别

  • READ UNCOMMITTED:读未提交。
  • READ COMMITTED:读已提交。
  • REPEATABLE READ:可重复读。
  • SERIALIZABLE:可串行化。

4.1 SQL 标准中的四种隔离级别

SQL 标准中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:

隔离级别脏读不可重复读幻读
READ UNCOMMITTED可能可能可能
READ COMMITTED-可能可能
REPEATABLE READ--可能
SERIALIZABLE--

4.2 MySQL中的隔离级别

不同的数据库厂商对 SQL 标准中规定的四种隔离级别支持不一样,比方说 Oracle 就只支持 READ COMMITTEDSERIALIZABLE 隔离级别。本书中所讨论的 MySQL 虽然支持 4 种隔离级别,但与 SQL 标准中所规定的各级隔离级别允许发生的问题却有些出入,MySQL在REPEATABLE READ隔离级别下,是可以禁止幻读问题的发生的

隔离级别脏读不可重复读幻读
READ UNCOMMITTED可能可能可能
READ COMMITTED-可能可能
REPEATABLE READ---
SERIALIZABLE--

Tips: MySQL的默认隔离级别REPEATABLE READ

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

我们可以通过下边的语句修改事务的隔离级别:

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level; 

其中的 level 可选值有 4 个:REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE

  • 使用 GLOBAL 关键字(在全局范围影响):
    比方说这样:

    SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    则只对执行完该语句之后产生的会话起作用。当前已经存在的会话无效

  • 使用 SESSION 关键字(在会话范围影响):
    比方说这样:

    SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    则对当前会话的所有后续的事务有效

该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务。

如果在事务之间执行,则对后续的事务有效

  • 上述两个关键字都不用(只对执行语句后的下一个事务产生影响):
    比方说这样:
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    则只对当前会话中下一个即将开启的事务有效。下一个事务执行完后,后续事务将恢复到之前的隔离级别。该语句不能在已经开启的事务中间执行,会报错的

文章作者: Kezade
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kezade !
评论
  目录