MYSQL之事务隔离级别与锁的关系

来源:互联网 发布:java 服务器文件同步 编辑:程序博客网 时间:2024/06/08 18:47

数据库的事物隔离级别说到底是为了把对同一table的读动作和写动作区别看来,实现方式当然就是加锁了。这里隔离级别是由加锁实现的。

首先回顾一下数据库事务隔离级别:


======================================================
隔离级别 脏读 不可重复读 幻读
======================================================
未提交读(read uncommitted) 可能 可能 可能
已提交读(read committed) 不可能 可能 可能
可重复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable) 不可能 不可能 不可能
======================================================

相信四种隔离级别的解释不用详细展开了,网上很多,简单说一下:

这里都是操作同一table
- 未提交读:可能读到未提交的数据(脏读),事务中查询的数据可能是另一事务未提交的数据,该数据随后可能被修改。
- 已提交读:只能读到已提交的数据,可能会造成同一事务中的两次相同查询结果不一致
- 可重复读:同一事务中的查询都是以事务开始状态为标准一直延续到该事务结束
- 可串行化:该级别每次读都会获得该表的共享锁,读写互相排斥。

针对MYSQL详细展开一下:

MYSQL常用的引擎有两种:MyIsAM和InnoDB,这两种引擎的功能区别在于:

1)myisam适合select,读取性能会高很多
2)innoDB适合update和insert,当对table的操作以写为主,选择它

两者的加锁机制分别为:
1)myisam只支持表级别锁
2)innoDb支持行级别锁

这里不要以为加锁级别不一样无所谓,问题太大了,下边我说下我遇到的问题,以此展开事务隔离级别。

前期规划项目的时候,考虑到表的操作是以查询为主,所以引擎改成MyIsAm,当然一直是我自己开发自己测试,所以对表的查询也没有并行的查询操作。但是,后续遇到了一个问题,就是随着业务需求扩大,我添加了批量查询和批量更新功能,当然批量查询是需要时间的,大约20min左右,在此期间,突然发现并行的批量阻塞了,
期间经过大量的分析和排查,发现我用的数据库默认的事务隔离级别是repeatable read这种隔离级别下的读操作是加读共享锁的,蛋疼的是,你要是加行级锁也就好了,这样能保证同一时间不对同一行进行读写操作,但………….Mysql的myisam只支持表级锁,呵呵,当在repeatable read级别下的读操作会加一个表级锁,OK,批量查询的期间,整个表被锁着了,当然锁是读共享,不影响其他事务的读取,但批量写操作就阻塞了

这里的解决方案就是:引擎我就不改了,因为业务需要我需要以查询为主,但要把读操作的锁去掉,就是读的时候不需要加锁,ok,只能把隔离级别由可重复读改成已提交读了。

经过上边的例子,相信可以对不同隔离级别的加锁方式有一定了解了

1)未提交读,容易产生脏读,不用
2)已提交读,读操作不加锁,写操作加写独占锁。当然这里的锁是行级锁的时候,不影响其他事务对之前数据的读取,但是myisam时,由于是表级别锁,会影响其他事务的读取,理论上是这样,但Myisam也不会这么白菜,insert过程中的读操作是可以的:

The MyISAM storage engine supports concurrent inserts to reduce contention between readers and writers for a given table: If a MyISAM table has no holes in the data file (deleted rows in the middle), an INSERT statement can be executed to add rows to the end of the table at the same time that SELECT statements are reading rows from the table.

3)可重复读:这种级别下的读操作要加锁的,当然myisam加的是表级锁。表级锁/行级锁下的读操作过程中是不能修改被锁住的数据的,当然行级别的锁不会影响修改别的数据。而表级锁锁住的是整个表就会影响写入操作了。这里的可以引入幻读了,所谓的幻读就是可重复读下的bug:可重复读的读操作锁住了读取的数据,这些数据不能被修改,但是,新的数据可以被插入到你读取的范围内啊,注意,新的数据插入了,当你读取完了,突然发现,咦,怎么凭空出现了一些新数据,这里就像幻觉一样。当然可串行化就是解决幻读的。
4)可串行化:就是我读的时候只给你加表级别锁,ok,不管你是修改还是insert,统统拒绝,等我读完再说

这里说一下如何修改mysql默认的isolation-level
我是linux系统:

mysql -u username -p password 进入mysql

mysql> set global transaction isolation level read committed;

ok;