什么是事务
事务是不可分割的数据库操作序列,是数据库并发访问的基本单位,其执行结果必定使数据库从一种一致性状态到另一种一致性状态,是逻辑上的操作,要么全部执行成功,要么全部执行失败。
事务的四大特性
- 原子性:原子不可在分割,要不全部执行成功,要不全部执行失败;
- 一致性:事务在提交前后,数据应保持一致,多个事务对数据的读取结果应该是一致的;
- 隔离性:多个事务并发访问数据库时,一个事务不会被其它事务所影响;
- 持久性:事务提交后,对数据库数据的改变是持久的。
脏读、不可重复读、幻读
- 脏读:一个事务对数据进行了更新,另一个事务对数据进行了读取,但是进行更新的事务又RollBack了,就导致另一个读取数据的事务读取到是数据是错误的。
- 不可重复读:一个事务在两次读取数据中读到的数据不一致,可能在这两次读取期间进行了数据更新的操作。
- 幻读:一个事务在两次读取数据中读到的数据笔数不一致,这有可能是在这两次读取期间又插入了几列新的数据,导致先读取的事务就会发现有几列数据是它没有的。
事务的隔离级别
- Read-UNCOMMITTED(读取未提交):最低的事务隔离级别,允许读取未提交的事务,可能会发生脏读,不可重复读,幻读。
- READ-COMMITTED(读取已提交):大多数数据库的默认隔离级别,但不是mysql的默认隔离级别,只允许读取已经提交的事务,不会发生脏读,但有可能会发生不可重复读和幻读。
- REPEATABLE-READ(可重复读):mysql的默认隔离级别,在多个事务并发读取数据时能保证读到的结果都是一致的,但是会发生幻读。
- SERIALIZABLE(可串行化):最高的事务隔离级别,强制给所有的事务排序,使它们不可能发生冲突。
MVCC
MVCC,也就是多版本并发控制,是一种并发控制方式,允许数据库操作管理系统并发的访问数据。
在mysql InnoDB存储引擎中就是指在事务隔离级别为READ-COMMITTED(读取提交事务)和REATABLE-READ(可重复读)时,事务对于select操作会在版本号中进行查询记录,这也就允许其他的事务并发的修改数据,反正每次操作都会在版本号中有记录。
mysql中的锁
按照锁的粒度来划分,可分为行级锁,表级锁,页级锁,InnoDB存储引擎支持行级锁和表级锁,默认为行级锁;MyISAM采用表级锁。
- 行级锁:对数据库中的行来加锁,特点是:开销大,加锁慢,锁的粒度是最小的,所以锁并发冲突的概率最低,并发能力最好,有可能会发生死锁。
- 表级锁:对整张表加锁,特点是:开销小,加锁快,锁的粒度最大,所以锁并发冲突的概率最高,并发能力最差,不会发生死锁。
- 页级锁:介于行级锁和表级锁之间,性能也都介于这两者之间,并且有可能会发生死锁。
按照锁的类别划分又可以分为共享锁和排它锁:
- 共享锁:又叫读锁,在进行读数据操作的时候会加锁,对同一数据可以加多把共享锁,也就是说共享锁是并发;
- 排它锁:又叫写锁,在进行写数据操作的时候会加锁,同一数据只能加一把排它锁,是互斥的,如果一个数据加了写锁,那就不能再加读锁和写锁。
InnoDB存储引擎锁的算法
补充一下:InnoDB存储引擎的行锁是通过索引来实现的。
- Record lock:单个行记录上的锁;
- Gap lock:间隙锁,锁定的是一个范围,不包括记录本身;
- Next-key lock:锁定的也是一个范围,但是包括记录本身。
死锁
什么是死锁?
- 两个或多个事务同时对同一资源竞争或互相持有对方想要申请的资源。
解决措施:
- 对于一个事务,尽量锁定该事务所需要的的全部资源,尽量一次性分配完;
- 如果多个事务对同一资源并发访问时,尽量让所有事务按照同一顺序来进行访问;
- 升级锁的粒度,升级为表级锁。
乐观锁和悲观锁
- 乐观锁:假定并不会发生并发冲突,所以只在数据要修改的时候进行数据的完整性检查,在修改数据时加上锁。适用于读多写少的场景。
- 悲观锁:假定会发生并发冲突,所以在查询完数据就会加上锁,直到事务提交后。因为写会修改数据,所以需要加锁,所以适用于写比较多的场景下。