mysql事务和锁机制
一、事务
1.事务的四大特性
? 事务的四大特性是ACID,分别是原子性、一致性、隔离性和持久性。
- 原子性:每一个事务都是最小的单位,一个事务中的操作要么完全成功,要么完全失败。
- 一致性:事务中的操作要符合逻辑,在事务操作之后不能破坏数据库的完整。
- 隔离性:事务之间是互不影响的、互不干扰的。
- 持久性:当事务提交之后,就持久到磁盘中了,是永久性的。
2.事务并发的三大问题
2.1 脏读
? 一个事务A读到了另外一个事务B修改但未提交的数据,导致事务A中两次读取的数据不一致,叫做脏读。
2.2 不可重复读
? 在一个事务中,两次执行相同的查询操作却得到了不一样的结果,是由于读取到其他的事务更新/删除提交后的数据,这种叫做不可重复读。
2.3 幻读
? 一个事务两次查询操作却得到了不同的结果,是由于读取到其他事务进行插入数据之后并提交后的数据,这种叫做幻读。
3.事务的四种隔离级别
? 由于事务并发的一些问题,mysql使用隔离级别来解决这些问题。
3.1 读未提交
? 未提交读是最低的隔离事务级别,如果一个事务正在进行写操作,那么其实事务不能进行写操作,但允许其他事务读这行数据。
? 一个事务会读到其他事务**未提交(commit)**的数据,这种隔离级别会产生脏读。
3.2 读已提交
? 在”读已提交“的隔离级别中,如果是读操作,那么允许其他事务进行读写;如果是写操作,那么不允许任何事务进行访问该行数据。
? 解决了脏读的问题,但是并没有解决不可重复读的问题。
3.3 可重复读
? 可重复读是InnoDB存储引擎的默认隔离级别,可重复读是指在一个事务中多次读取同一个数据,在这个事务还没有结束的时候,其他事务不能访问该数据(包括读写),这样就会保证事务在多次读取一个数据时的信息时一致,解决了脏读和不可重复读的问题。
? 在InnoDB存储引擎中,使用Next-Key Lock锁的算法或者MVCC,避免的幻读的问题。
3.4 串行化
? 串行化是事务的最高隔离级别,要求事务序列化执行,一个一个执行,不能并发执行,就不会出现脏读、不可重复读和幻读的问题,但是会导致效率太慢。
二、锁机制
1.行锁
1.1 共享锁(S锁)
定义
? 又称读锁,顾名思义,共享锁就是多个事务对于一个同一个数据可以共享一把锁,都能访问的数据,但是只能读不能修改。
加锁方式(SQL)
select * from user where id = 1 lock in share mode
commit/rollback
1.2 排他锁(X锁)
定义
? 又称为写锁,排他锁不能与其他锁共存,如一个事务获取了一行数据的排他锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有获取了排他锁的事务才能对该数据进行读取和修改。
加锁方式(SQL)
delete/update/insert 默认加锁
select * from user where id=1 for update;
2.表锁(意向锁)
? 意向锁是数据库自己维护的,用户无法手动操作意向锁,可以理解意向锁是一个标志,并不是一个实质性的锁。
2.1 为什么需要意向锁?
- 探路:InnoDB共享锁、排他锁是行锁,事务操作到行才发现被锁,非常耗费资源和浪费时间,因此表级的意向锁就很重要了。
- 排他:在事务锁定某行前,先对表施加意向共享锁或意向排他锁,后来的事务就很方便知道自己是否可以施加某种锁了。
2.2 意向共享锁
? 表示事务准备给一行数据加入共享锁,也就是说一个数据行加共享锁前必须先获得该表的IS锁。
2.3 意向排他锁
? 表示事务准备给一行数据加入排他锁,也就是说一个数据刚要想加入一个排他锁前必须先获得该表的IX锁。
3.锁的原理
? 加锁其实就是将锁加到了索引上。
4.InnoDB处理幻读
4.1 记录锁(Record)
? 记录锁总是会锁住索引记录,如果InnoDB存储引擎表在简历的时候没有设置任何一个索引,那么这是InnoDB存储引擎会使用隐式的主键进行锁定。
select * from user where id=4 for update;
4.2 间隙锁(Gap)
? 不是针对某一记录加锁,而是锁定一个范围,不会阻塞其他gap锁,但会阻塞插入间隙锁,这也是防止幻读的关键。
select * from user where id>4 and id<7 for update
select * from user where id=6 for update
4.3 临键锁(Next-key)
? 临键锁就是记录锁+间隙锁,并且锁定记录本身,InnoDB的幻读就是由这个解决的。
|