文章目录
- 事务隔离级别
- 执行 SQL 语句,查看数据库的事务隔离级别
- 修改配置文件,改变数据库的事务隔离级别(永久)
- 执行 SQL 语句,修改数据库的事务隔离级别(临时)
- 读未提交 read uncommitted
- 读已提交 read committed
- 可重复读 repeatable read
- 串行化 serializable
事务隔离级别
执行 SQL 语句,查看数据库的事务隔离级别
mysql> show variables like 'transaction_isolation';
修改配置文件,改变数据库的事务隔离级别(永久)
[mysqld]
...
# transaction-isolation=READ-UNCOMMITTED
# transaction-isolation=READ-COMMITTED
# transaction-isolation=REPEATABLE-READ
# transaction-isolation=SERIALIZABLE
默认是 REPEATABLE-READ 。修改配置文件后记得要重启 MySQL Server 。
执行 SQL 语句,修改数据库的事务隔离级别(临时)
-- SQL命令:对当前会话生效。会话断开、重连后失效。
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
-- SQL命令:对后续会话生效。MySQL Server 重启后失效。
set global transaction isolation level read uncommitted;
set global transaction isolation level read committed;
set global transaction isolation level repeatable read;
set global transaction isolation level serializable;
验证时注意两点:
- 记得关闭自动提交功能:
mysql> set autocommit = off;
- 最好使用命令行黑窗口进行验证。因为有些图形化工具会复用 session ,导致你看不到预期效果。
读未提交 read uncommitted
读未提交隔离级别意味着我(当前事务)在事务执行期间,能看到别人(另一个事务)还未提交的数据。
验证(A 事务是「别人」,正常执行,无需考虑其它;B 事务是「我」,会受 A 事务的影响):
- A 事务和 B 事务分别开始(
mysql> begin;
); - A 事务执行 update 语句。此时,A 事务未提交(commit);
- B 事务执行 select 语句,你会发现 B 事务查到的是 A 事务修改的但未提交的数据。
- …
「我读到了别人未提交的数据」这种现象也被称为脏读。读未提交隔离级别在生产环境中不具有使用价值。
读已提交 read committed
读已提交隔离级别解决了读未提交级别的问题。
读一今提交隔离级别意味着我(当前事务)在事务执行期间,只能看到别人(另一个事务)已经提交的数据,它改动了的但未提交的数据对我而言不可见。
验证(A 事务是「别人」,正常执行,无需考虑其它;B 事务是「我」,会受 A 事务的影响):
- A 事务和 B 事务分别开始(
mysql> begin;
); - A 事务执行 update 语句。此时,A 事务未提交(commit);
- B 事务执行 select 语句,你会发现 B 事务查到的还是老数据,即 A 事务改动前的数据;
- A 事务提交后,B 事务再次执行 select 语句,此时你会发现 B 事务现在查到的才是 A 事务改动后的数据。
- …
读已提交 read commited 时很多数据库的默认事务隔离级别,例如 Oracle 和 PostgreSQL 。
可重复读 repeatable read
前一个隔离级别有一个问题(当然,有些人认为这不是个问题,只能算是个现象):在 B 事务执行期间,因为 A 事务的提交,导致 B 事务在 A 事务提交前后执行同样的 select 语句会看到不同的数据内容。
站在「上帝视角」你会觉得这很正常,如果单站在 B 的视角就有点怪怪的感觉:我明明没有动这个数据,它怎么突然就变了?
可重复读隔离级别解决了这个问题:我(当前事务)在事务执行期间,当我 select 一个数据之后,无论别人(另一个事务)有没有改动这个数据,我再次 select 这个数据仍然会看到我第一次看到的那个样子。
验证(A 事务是「别人」,正常执行,无需考虑其它;B 事务是「我」,会受 A 事务的影响):
- A 事务和 B 事务分别开始(
mysql> begin;
); - B 事务执行 select 语句,查询某条数据;
- A 事务执行 update 语句并提交,改动同一条数据;
- B 事务再次执行同样的 select 语句,查询之前查询过的数据,会看到仍然是改动前的数据;
- B 事务提交;
- 这时 B 再查询,才会看到 A 改动后的数据(之前不会)。
可重复读 repeatable read 是 MySQL 的默认隔离级别。其实,MySQL 之所以默认隔离级别要高一些是因为 MySQL 的实现缺陷导致在某些极端情况下使用读已提交 read committed 会出问题,所以,MySQL 迫于无奈才只能提升默认隔离级别等级。
串行化 serializable
串行化 serializable 是最高级别的隔离级别。这种级别下,一个事务中的 SQL 语句的执行会因为另一个事务而阻塞等待。
验证(A 事务是「别人」,正常执行,无需考虑其它;B 事务是「我」,会受 A 事务的影响):
- A 事务和 B 事务分别开始(
mysql> begin;
); - A 事务执行 update 语句,此时未提交;
- B 事务执行 select 语句,你会发现有类似「卡死、无反应」的现象,实际上是 B 事务的 select 语句在等待;
- A 事务执行提交;
- 这个时候,B 事务之前执行的 select 语句的查询结果才出来。