1.什么是事务?
一组逻辑操作单元,使数据从一种状态变换到另一种状态
2.事务的ACID特性
- 原子性
指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚
- 一致性
事务执行前后,数据从一个合法性状态变换到另一个合法性状态。这种状态跟具体的业务有关,通俗的说,这状态是你自己定义的,满足这个状态,数据就是一致的,不满足这个状态,就是不一致的
- 隔离性
指一个事务的执行不能被其他事务干扰,即一个事务的内部操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
- 持久性
指一个事务一旦被提交,它在数据库中对数据的改变是永久性的,接下来的其他操作和数据库的故障不应该对其有任何影响
事务的隔离性由锁机制实现,而事务的原子性,一致性和持久性由事务的redo日志和undo日志来保证
3.SQL中的四种隔离级别
- READ UNCOMMITTED:读未提交
- READ COMMITTED:读已提交
- REPETABLE READ:可重复读(默认隔离级别)
- SERIALIZABLE:可串行化
4.MySQL锁的分类
- 从数据操作的粒度划分:表级锁,行级锁,页级锁
表锁
(1)表级别的S锁,X锁
(2)意向锁
(3)自增锁
(4)元数据锁
行锁
(1)记录锁
仅仅把一条记录锁上
(2)间隙锁
MySQL在默认隔离级别下是可以解决幻读问题的,解决方案有两种,可以使用MVCC方案,也可以采用加锁方式解决(间隙锁),间隙锁的提出仅仅是为了防止插入幻影记录而提出的。
(3)临键锁
有时候我们既想锁住某条记录,又想阻止其他事务在该记录的前边间隙插入新纪录,所以InnoDB提出临键锁。临键锁是在存储引擎 InnoDB,事务级别在可重复读的情况下使用的数据库锁,也是InnoDB引擎默认的锁。
(4)插入意向锁
- 从对待锁的态度划分:乐观锁,悲观锁
悲观锁总是假设最坏的情况,每次拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿到这个数据就会阻塞。比如行锁,表锁,读锁,写锁等,都是在做操作之前上锁。Java中的synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。悲观锁适合写操作多的场景。
乐观锁不用每次都对数据上锁,但是在更新的时候会判断一下此期间别人有没有更新这个数据。乐观锁不采用数据库自身的锁机制,而是通过程序去实现的。可以使用版本号机制或CAS实现。乐观锁适用于多读的情形,可以提高吞吐量。
- 按加锁的方式划分:显示锁,隐式锁
- 全局锁
- 死锁
5.MVCC
查询一条记录的时候,系统如何通过MVCC找到它:
1. 首先获取事务自己的版本号,也就是事务 ID;
2. 获取 ReadView;
3. 查询得到的数据,然后与 ReadView 中的事务版本号进行比较;
4. 如果不符合 ReadView 规则,就需要从 Undo Log 中获取历史快照;
5. 最后返回符合规则的数据。
在隔离级别为读已提交(Read Committed)时,一个事务中的每一次 SELECT 查询都会重新获取一次ReadView。而在可重复读的隔离级别下,一个事务只在第一次SELECT的时候会获取一次ReadView,而后面所有的SELECT都会复用这个ReadView,通过ReadView规则机制解决了幻读的问题。