MySQL Transactions, Part II - Transaction Isolation Levels

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介:
August 17, 2004

MySQL Transactions, Part II - Transaction Isolation Levels

By Ian Gilfillan

Last month we started looking at transactions in MySQL, in particular with InnoDB tables. This month we look at the four transaction isolation levels, again with InnoDB tables, and see how they affect the usual locking transactional behavior.

Transaction Isolation Levels

A transaction isolation level sets the default transactional behaviour. Our examples last month all took the default setting. This month, we see how changing the transaction isolation level leads to different results. As the name suggests, the setting determines how isolated each transation is, or what kind of locks are associated with queries inside a transaction. The four levels, in ascending order of strictness, are:

  • READ UNCOMMITTED: Barely transactional, this setting allows for so-called 'dirty reads', where queries inside one transaction are affected by uncommitted changes in another transaction.
  • READ COMMITTED: Committed updates are visible within another transaction. This means identical queries within a transaction can return differing results. This is the default in some DBMS's.
  • REPEATABLE READ: The default isolation level for InnoDB tables. Within a transaction, all reads are consistent.
  • SERIALIZABLE: Updates are not permitted in other transactions if a transaction has run an ordinary SELECT query, i.e. queries are treated as if they had a LOCK IN SHARE MODE, which we saw in action last month.

InnoDB tables support all four SQL standard transaction isolation levels. Be careful when converting code from other DBMS's, as they do not all support all four levels, nor do they all default to the same level.

  • SQL SERVER - READ COMMITTED
  • Oracle - READ COMMITTED (supports only READ COMMITTED, SERIALIZABLE and the non-standard READ ONLY)
  • DB2 - REPEATABLE READ (supports REPEATABLE READ, UNCOMMITTED READ and 2 non-standard levels)
  • PostgreSQL - REPEATABLE READ (only supports REPEATABLE READ and SERIALIZABLE)

For those who have skipped Part 1, we are using the following table to test with:

mysql> DESC t;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| f     | int(11) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.05 sec)

You can create and populate it as follows:

mysql> CREATE TABLE t (f INT) TYPE = InnoDB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t values (1),(2),(3),(4),(55);
Query OK, 5 rows affected (0.00 sec)

If you have not made a specific change to the transaction isolation level, it will be a repeatable read. You can check this as follows:

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

Repeatable Reads

In this exercise, we begin a transaction, and see if a committed insert from another transaction is visible in the midst of the transaction.

Connection 1

mysql> BEGIN;
Query OK, 0 rows affected (0.05 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
+------+
5 rows in set (0.00 sec)

Connection 2

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES(6);
Query OK, 1 row affected (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

Remember that it does not matter to the second connection that the SELECT statement was run after the COMMIT. Within the transaction, the new record is immediately visible.

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
+------+
5 rows in set (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

This is the essence of the repeatable read. The SELECT query returns a consistent result within a transaction, and new records added from another window during the transaction are not immediately visible. For a result to be visible, both the updating transaction, and any transactions that are already open, needs to be committed.

Uncommitted Reads

Let's see what happens with the READ UNCOMMITTED transaction isolation level. To change this, you will need to have the SUPER privilege.

mysql> SET GLOBAL TRANSACTION ISOLATION 
  LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

Use two new connections for the exercise below, as the new transaction isolation level takes effect only for new connections made after the command is run.

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

Connection 2:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES (7),(8);
Query OK, 1 row affected (0.06 sec)

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
|    7 |
|    8 |
+------+ 6 rows in set (0.00 sec)

This is known as a dirty read - the new records have not even been committed by the second transaction, yet they are still visible to the first transaction.

Connection 2:

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

There are dangers with this level of isolation and it bends the rules of transactions. You would only want to use this where you really do not care about the consistency of your results, but do care about potential locks impacting performance.

Committed Reads

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)

Connection 1:

mysql>BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

Connection 2:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES (7),(8);
Query OK, 1 row affected (0.05 sec)

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
+------+
6 rows in set (0.00 sec)

Connection 2:

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

Connection 1:

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
|    7 |
|    8 |
+------+
8 rows in set (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

The important difference is that an uncommitted INSERT did not have any impact on the transaction in Connection 1. Once the second connection's transaction was committed, the result was visible in the first transaction. It is also important to distinguish the difference between this and the default repeatable read transaction isolation level we saw at the beginning. With READ COMMITTED, changes are visible when other transactions commit them. With REPEATABLE READ, changes are only visible when both other transactions commit them, and only in a new transaction. Understanding this important point brings you to the essence of the difference between the two states.

Serializable

Serializable takes locking a step further than even REPEATABLE READ. In this state, all plain SELECT queries are treated as if they had a LOCK IN SHARE MODE appended.

Connection 1:

mysql> BEGIN;
Query OK, 0 rows affected (0.06 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
|    7 |
|    8 |
+------+
8 rows in set (0.06 sec)

Connection 2:

mysql> BEGIN;
Query OK, 0 rows affected (0.06 sec)

mysql> UPDATE t SET f=88 WHERE f=8;


Because of the SELECT statement from the first connection, the UPDATE is locked, just as with an ordinary LOCK IN SHARE MODE. Only once the first transaction is committed does the UPDATE take place.

Connection 1:

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

Connection 2:

Query OK, 1 rows affected (4.23 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
|    7 |
|   88 |
+------+
8 rows in set (0.00 sec)

Conclusion

Repeatable reads makes sense as a default transaction isolation level, and in most cases, you are unlikely to want to change this. Locking issues can lead to endless hours of fun if you are not careful and do not take note of the subtleties. Next month we will continue our look at MySQL transactions, focusing on other table types.

转自:MySQL Transactions, Part II - Transaction Isolation Levels

本文转自 zhenjing 博客园博客,原文链接:http://www.cnblogs.com/zhenjing/archive/2011/02/15/MySQL-Transactions-Part-II.html    ,如需转载请自行联系原作者

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
分布式计算 关系型数据库 MySQL
MaxCompute产品使用合集之用flink mysql的数据同步到mc的Transaction Table2.0,时间会比mysql的时间多8小时,是什么导致的
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
187 0
|
SQL 存储 关系型数据库
MySQL技能完整学习列表8、触发器、视图和事务——1、触发器(Triggers)的使用——2、视图(Views)的创建和使用——3、事务(Transactions)的管理
MySQL技能完整学习列表8、触发器、视图和事务——1、触发器(Triggers)的使用——2、视图(Views)的创建和使用——3、事务(Transactions)的管理
328 0
|
关系型数据库 MySQL 数据库
MySQL报错:Lock wait timeout exceeded; try restarting transaction
MySQL报错:Lock wait timeout exceeded; try restarting transaction
1785 0
|
SQL 关系型数据库 MySQL
MySQL报错:1205 Lock wait timeout exceeded; try restarting transaction处理
MySQL报错:1205 Lock wait timeout exceeded; try restarting transaction处理
995 0
|
SQL 关系型数据库 MySQL
【MySQL异常】MySQL事务锁问题----lock wait timeout exceeded; try restarting transaction
【MySQL异常】MySQL事务锁问题----lock wait timeout exceeded; try restarting transaction
1323 0
|
SQL 关系型数据库 MySQL
Mysql 异常:Lock wait timeout exceeded; try restarting transaction的解决办法
Mysql 异常:Lock wait timeout exceeded; try restarting transaction的解决办法
923 0
|
SQL 关系型数据库 MySQL
mysql Lock wait timeout exceeded; try restarting transaction解决方案
在测试程序时,打的断点怎么都跳不进去,console一直报 “Lock wait timeout exceeded; try restarting transaction”
423 0
|
SQL 关系型数据库 MySQL
Mysql——事务详解(Transaction)
Mysql——事务详解(Transaction)
Mysql——事务详解(Transaction)
|
关系型数据库 MySQL 数据库
MySQL - Lock wait timeout exceeded; try restarting transaction
MySQL - Lock wait timeout exceeded; try restarting transaction
707 0
MySQL - Lock wait timeout exceeded; try restarting transaction
|
SQL 关系型数据库 MySQL
一文带你明白“MySQL事务(transaction)”
一文带你明白“MySQL事务(transaction)”
一文带你明白“MySQL事务(transaction)”

推荐镜像

更多