mysql事务隔离级别
MYSQL的锁
1. 共享锁,也就是读锁,可以通过select ... lock in share mode强制加锁,默认select语句是不加锁的
2. 排他锁,也就是写锁,可以通过select ... for update强制加写锁,默认情况下insert, update, delete语句加写锁
MYSQL锁的粒度
1. 行锁,锁一行,并发高(因为冲突少),开销小,会产生死锁,innodb引擎
2. 表锁,锁全表,并发低(因为冲突多),开销大,不会产生死锁,myisam, memory引擎,所以myisam没有事务,也是不会数据库死锁的,在执行SQL前做一次锁定好所需资源,但是myisam可能会因为大量的表级别的写锁导致无法获取到读锁从而对读阻塞
3. 页锁,对杭锁和表锁的一种折中,锁一批相邻的记录,在并发和开销上介于行级锁和表锁中间,也会产生死锁,bdb数据库
Innodb存储引擎
由于Innodb有MVCC,所以select ...的时候是不加锁的,直接读最新版本的数据
select语句强制指定锁的时候回加锁,还有就是insert, update, delete的时候要加锁
事务隔离级别
事务隔离级别可以理解为描述了多个事务同时发生时候对数据的锁定级别,这是在并发能力和交叉事务上表现的一种折中,在标准SQL中一共有四种事务隔离界别
四个隔离级别有两个工程中几乎不用
read uncommited,未提交读
从名字上记忆就是,事务还没提交,其他事务中就观测到了数据的修改,没人想用这个,针对别人还没提交就读取到的这种现象叫做脏读
serialiazble,串行化
读写是冲突的,所以变成了串行,没有并发,这个也没人用
还有两个隔离级别,是常用的
read commited,提交读,简称RC隔离级别
这个级别解决了read uncommited脏读的问题,对读取的数据加读锁,读完立刻释放,对写的数据加写锁,直到事务结束写锁才释放。这样就不会产生脏读。但是会产生一次事务内写锁加锁前读取两次读取数据不一致的情况,这种不一致情况叫做不可重复读
repeatable read,可重复读,简称RR隔离级别(MYSQL默认的事务隔离级别)
这个级别解决了read commited两次读取数据可能不一致的问题,解决的方法就是读加读锁,直到事务结束才释放,写加写锁,直到事务结束才释放。这样就不会产生两次读的数据不一致,因为读锁的释放时间增加了,保证了在读的时候是不可以有人来改变数据的。
如果是通过简单的行级锁的机制来实现RR隔离级别,那么在数据插入的时候会产生问题,比如事务1做一个范围查询,但是事务2在这个事务内插入了一条数据,并提交,事务1再做范围查询的时候回查询到事务2新增的数据,这个也是一种两次读取数据不一致的情况,但是这个不叫不可重复读,叫做幻读。
MYSQL在RR隔离级别下可以通过GAP锁来解决幻读,也就是加行锁的时候不是只对某一行加锁,而是根据索引,把相邻的索引区间加锁,这样在相邻区间上进行insert的时候,需要等待,这种GAP区间的大小也有可能最后变成锁全表