MySQL Transaction Isolation Level

本文深入解析了四种SQL标准事务隔离级别:读未提交、读已提交、可重复读和序列化,探讨了每种级别的特点、锁机制及对性能的影响,并讨论了其在复制和应用选择中的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Isolation LevelPhantom readNonrepeatable readDirty read
Read uncommittedPossiblePossiblePossible
Read committedPossiblePossibleNot possible
Repeatable readPossibleNot possibleNot possible
SerializableNot possibleNot possibleNot possible
  • A phantom read occurs when a transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.
  • A non-repeatable read occurs when a transaction re-reads data it has previously read and finds that data has been modified by another transaction that committed since the initial read.
  • A dirty read occurs when a transaction reads data from a row that has been modified by another transaction, but not yet committed.

Isolation is an important part of ACID properties that guarantee that transactions are processed in a reliable manner. Isolation ensures that concurrently running transactions do not interfere with each other. Isolation ensures data consistency. If the transactions are not isolated then one transaction could modify data that other transactions are reading hence creating data inconsistency.

Now that we have understood what isolation is let’s understand isolation levels. Isolation levels determine how isolated the transactions are from each other, it could be that there is no isolation or the maximum level of isolation which serializes transactions execution. Selecting the best isolation level really depends on your application needs, but for that you must first understand all the different isolation levels and the consequences of selecting any one of them.

InnoDB supports all the four SQL-standard isolation levels, which are listed and described in the following text.

READ UNCOMMITTED

With the READ-UNCOMMITTED isolation level there isn’t much isolation present between the transactions at all. The transactions can see changes to data made by other transactions that are not committed yet. That means transactions could be reading data that may not even exist eventually because the other transaction that was updating the data rolled-back the changes and didn’t commit. This is known as dirty read. An application rarely needs to rely on dirty needs, in fact this really can’t be called an isolation level. Simply put, there isn’t really any isolation at all and hence such a system can’t really be called a transactional system.

READ COMMITTED

With the READ-COMMITTED isolation level, the phenomenon of dirty read is avoided, because any uncommitted changes is not visible to any other transaction, until the change is committed. Within this isolation level each SELECT uses its own snapshot of the committed data that was committed before the execution of the SELECT. Now because each SELECT has its own snapshot, so the same SELECT when run multiple times during the same transaction could return different result sets. This phenomenon is called non-repeatable read.

REPEATABLE READ

With the REPEATABLE-READ isolation level, the phenomenon of non-repeatable read is avoided. This isolation level returns the same result set through out the transaction execution for the same SELECT run any number of times. A snapshot of the SELECT is taken the first time that SELECT is run during the transaction and the same snapshot is used through out the transaction when the same SELECT is executed. A transaction running in this isolation level does not take into account any changes to data made by other transactions, regardless of whether the changes have been committed or not. This ensures that reads are always consistent(repeatable). This isolation level is the default for InnoDB. Although this isolation level solves the problem of non-repeatable read, but there is another possible problem phantom reads.

SERIALIZABLE

With the SERIALIZABLE isolation level, the phenomenon of phantom reads is avoided. Transactions when run in this isolation level place locks on all records that are accessed, as well as locks the resource so that records cannot be appended to the table being operated on by the transaction. Transactions when run in this fashion, run in a serialized manner. This isolation level is the strongest possible isolation level.

SERIALIZABLE isolation level can be pretty much avoided!

As the text above describes, phantom reads is the only problem that SERIALIZABLE is helping you avoid, otherwise SERIALIZABLE is pretty much same as REPEATABLE-READ. InnoDB has a special locking feature called gap-locking which helps you avoid the phantom reads problem. In the case of gap locking, a lock is set on the gap between index records, or on the gap before the first or after the last index record. Now all you have to do avoid phantom reads is to convert such reads to locking reads using SELECT with FOR UPDATE or LOCK IN SHARE MODE.

Locking and the isolation levels

The READ-UNCOMMITTED isolation level has the least number of locking done, after that comes the READ-COMMITTED isolation level which removes most of the gap-locking and hence produces fewer deadlocks, also in the case of READ-COMMITTED, locking reads only lock the index records and not the gaps before/after them. REPEATABLE-READ has a higher level of locking as compared to READ-COMMITTED, UPDATE, DELETE use next-key locking, also locking reads also use next-key locking. SERIALIZABLE has the highest level of locking, all the simple SELECTs are automatically converted to SELECT … LOCK IN SHARE MODE, and hence all records have shared locks.

Replication and isolation levels

The default replication type in MySQL is statement-based replication, and this replication type replicates the data changes by re-executing SQL statements on slaves that were executed on the master. This requires the isolation level to be stricter (involving more locking) so that the data changes are consistent in such a way that the same SQL when executed on the slave produces the same data changes. As mentioned above, READ-COMMITTED creates a situation of non-repeatable read, hence its not safe for statement-based replication. Hence, when using statement-based replication either use SERIALIZABLE or REPEATABLE-READ isolation level. If you have MySQL version >= 5.1 then you can use READ-COMMITTED with the row-based replication, because with row-based replication you have exact information about each data row changes.

Performance and isolation levels

As I have mentioned in the “Locking and the isolation levels” section, SERIALIZABLE and REPEATABLE-READ employ lots of locking and hence creating more deadlock situations, which in turn decreases performance. In fact SERIALIZABLE is the least performant of the isolation levels, as it converts even plain reads into locking reads. REPEATABLE-READ is better in terms of locking and deadlocks but READ-COMMITTED is even better because there are fewer gap-locks. But locking and deadlocks is not the only thing when considering performance, there is another issue of mutex contention that needs consideration. There is a post by Mark Callaghan comparing both REPEATABLE-READ and READ-COMMITTED in the context of mutex contention. This post can be found here.

Conclusion

I have tried to provide a detailed description of the four isolation levels and causes and effects of using any one of them, I have also mentioned locking and performance as related to the isolation levels. Now READ-COMMITTED and REPEATABLE-READ really are the only two isolation levels from which to make your selection. And that selection really depends on the kind of application you are running. I don’t think any generalized benchmark would help you make the selection between the two. So before making any decision run benchmarks specific to your application and then try to make a decision. I also sincerely hope that you are running MySQL version >= 5.1, because if you are running any other version REPEATABLE-READ is pretty much your only choice.

### 如何在 MySQL 中修改事务隔离级别 #### 方法一:通过 SQL 查询语句动态修改 可以使用 `SET` 语句来临时更改当前会话或全局的事务隔离级别。这种修改仅对当前会话有效,或者如果设置了全局变量,则会影响新建立的连接。 以下是具体的语法: ```sql -- 设置当前会话的事务隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}; -- 设置全局事务隔离级别 SET GLOBAL TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}; ``` 例如,将当前会话的事务隔离级别更改为 `READ COMMITTED`: ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` 可以通过以下命令验证更改是否生效: ```sql SELECT @@session.transaction_isolation; ``` 这种方法的优点在于无需重启服务即可立即生效,但缺点是每次服务器重启后都会恢复到默认值[^1]。 --- #### 方法二:通过配置文件永久修改 为了使事务隔离级别的更改持久化,可以在 MySQL 配置文件中进行设置。通常情况下,该文件位于 `/etc/my.cnf` 或其他指定路径下。 编辑配置文件,在 `[mysqld]` 节点下添加或修改如下内容: ```ini [mysqld] transaction-isolation = READ-COMMITTED ``` 保存并关闭文件后,需重新启动 MySQL 服务以应用更改: ```bash sudo systemctl restart mysql ``` 完成上述操作后,可通过以下命令确认新的隔离级别已成功应用: ```sql SHOW VARIABLES LIKE 'transaction_isolation'; ``` 此方法适用于希望长期保持特定隔离级别的场景,且不会因服务器重启而丢失配置[^2]。 --- #### 支持的事务隔离级别及其含义 MySQL 提供了四种标准的事务隔离级别,每种都有其独特的特性与适用范围: - **READ UNCOMMITTED**: 允许读取未提交的数据变更,可能导致脏读现象。 - **READ COMMITTED**: 只能读取已经提交的数据,解决了脏读问题,但仍可能遇到不可重复读的情况。 - **REPEATABLE READ**: 默认隔离级别,确保同一事务中的多次相同查询返回一致的结果,防止不可重复读,但可能存在幻读。 - **SERIALIZABLE**: 最高的隔离级别,完全串行化处理事务,避免所有并发问题,但性能开销较大[^4]。 --- #### 创建多线程环境测试隔离级别效果 为了观察不同隔离级别下的行为差异,可按照以下步骤设计实验: 1. 使用两个独立的客户端连接至数据库; 2. 在其中一个客户端开启事务,并执行某些数据更新操作而不提交; 3. 切换至另一个客户端尝试读取这些尚未提交的数据; 4. 根据不同的隔离级别设定,记录所观察到的行为变化。 这有助于深入理解各隔离级别之间的区别以及它们解决的具体问题[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值