标签:mysql事务的隔离级别
ANSI SQL标准制定了四种事务隔离级别,但是很少有数据库厂商遵循这些标准。四个隔离级别为:
级别 | 名称 | 说明 |
1 | READ UNCOMMITTED | 被称为浏览访问(browse access),仅仅是对事务而言 |
2 | READ COMMITTED | 被称为游标稳定(cursor stability) |
3 | REPEATABLE READ | 是2.99990的隔离,没有幻读保护(innodb默认隔离级别) |
4 | SERIALIZABLE | 被称为隔离,或者30的隔离 |
SQL和SQL2标准的默认事务隔离级别是SERIALIZABLE。INNODB存储引擎与标准SQL不同的是,在REPEATABLE READ事务隔离级别下,使用next-key lock的锁算法,因此避免了幻读的产生,已经能够完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE的隔离级别。
隔离级别越低,事务请求的锁越少或者保持锁的时间越短。这也是为什么大多数数据库系统默认的事务隔离级别是READ COMMITTED的原因。
在InnoDB存储引擎中,设置隔离级别的语法如下:
SET [GLOBAL|SESSION] TRANSACTIONISOLATION LEVEL {READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE}
mysql>set session transaction isolation level read committed;
Query OK,0 rows affected (0.00 sec)
mysql>select @@tx_isolation;
+----------------+
|@@tx_isolation |
+----------------+
|READ-COMMITTED |
+----------------+
1 row inset (0.00 sec)
或者使用参数
SET tx_isolation = ‘{READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-READ|SERIALIZABLE}‘;
mysql>set tx_isolation =‘READ-UNCOMMITTED‘;
Query OK,0 rows affected (0.00 sec)
mysql>select @@tx_isolation;
+------------------+
|@@tx_isolation |
+------------------+
|READ-UNCOMMITTED |
+------------------+
1 row inset (0.00 sec)
在配置文件[mysqld]中的选项为:
transaction-isolatio = {READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-READ|SERIALIZABLE}
(1)查看当前会话的隔离级别
mysql>select @@tx_isolation;
+-----------------+
|@@tx_isolation |
+-----------------+
|REPEATABLE-READ |
+-----------------+
1 row inset (0.00 sec)
(2)查看全局的事务隔离级别
mysql>select @@global.tx_isolation;
+-----------------------+
|@@global.tx_isolation |
+-----------------------+
|REPEATABLE-READ |
+-----------------------+
1 row inset (0.00 sec)
(一)SERIALIZABLE事务隔离级别
在SERIALIZABLE的事务隔离级别下,innodb会对每个select语句后自动加上LOCK IN SHARE MODE,即给每个读加一个共享锁。在这个事务隔离级别下,读占用锁了,因此对于一致性的非锁定读不再予以支持。由于innodb存储引擎在REPEATABLE READ隔离级别下就可以达到30的隔离,因此一般不在本地事务中使用SERIALIZABLE隔离级别,SERIALIZABLE隔离级别主要用于INNODB存储引擎的分布式事务。
(二)READCOMMITTED事务隔离级别
在READCOMMITTED事务隔离级别下,除了唯一性的约束检查及外键约束的检查需要gap lock,InnoDB存储引擎不会使用gap lock的锁算法。
但是使用这个事务隔离级别需要注意一些问题。
(1)隔离级别对二进制日志的影响
在MySQL5.1中,READ COMMITTED事务隔离级别默认只能工作在Replication的二进制日志为Row格式下,如果格式为STATEMENT则会报错。
在MySQL5.0之前的版本不支持Row格式的二进制日志,将参数innodb_locks_unsafe_for_binlog=1来实现可以在二进制日志为STATEMENT下使用READ-COMMITTED的事务隔离级别。
mysql>show variables like ‘innodb_locks_unsafe_for_binlog‘;
+--------------------------------+-------+
|Variable_name | Value |
+--------------------------------+-------+
|innodb_locks_unsafe_for_binlog | OFF |
+--------------------------------+-------+
1 row inset (0.00 sec)
但是该参数在某些情况下是不安全的,可能会导致master和slave之间数据的不一致。诸如使用该事务级别时,两个事务同时运行, 在第一个事务在删除并没有提交的情况下,第二个事务做了删除条件下的插入数据并提交,在第一个事务提交后,可以看到slave上的数据并没有插入进去。
原因有两点:
l 在READ COMMITTED事务隔离级别下,事务是没有Gap Lock锁的。因此可以在删除条件下插入记录;
l STATEMENT记录的是MASTER上产生的SQL语句,因此在master服务器上执行的顺序是先删后插,但是在STATEMENT格式中记录的却是先插后删,逻辑上就产生了不一致。
要避免主从不一致的问题,只需解决上述问题的一个就能保证数据的同步。对于第一种情况,修改隔离级别为REPEATABLE READ事务隔离级别。
在5.1版本之后,支持ROW格式,能够避免第二种情况的发生,但是即使不适用READ COMMITTED的事务隔离级别,也应该考虑将二进制日志的格式更换成ROW,因为这个格式记录的是行的变更,而不是简单的SQL的变更。
标签:mysql事务的隔离级别
原文地址:http://gfsunny.blog.51cto.com/990565/1574052