一、锁
1)锁是数据库系统区别于文件系统的一个关键特性,数据库使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性。
2)每一种数据库实现锁的方式都不同。
共享锁:允许事务读一行数据。当一个事务获得行h的共享锁,那么另外的事务也可以立即获得行h的共享锁,这种情况叫锁兼容
排他锁:允许事务删除或更新一行数据。在上面的情况中,如果有事务想要获取行h的排他锁,则必须等待事务释放行h上的共享锁。这种情况叫锁不兼容
为支持在不同粒度上进行加锁操作,InnoDB存储引擎还支持一种额外的锁方式:意向锁,InnoDB支持两种意向锁:
意向共享锁:事务想要获取表中某几行的共享锁
意向排他锁:事务想要获取表中某几行的排他锁
查看当前事务中锁的情况,可使用以下三张表(MySQL 5.7中已经不提倡使用,这几种表已经deprecated):
l INFORMATION_SCHEMA.INNODB_TRX
l INFORMATION_SCHEMA.LOCKS
l INNODB_LOCK_WAITS
1、一致性的非锁定读操作(重点)
指InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE、UPDATE操作,这时读取操作不会因此而会等待行上锁的释放,相反,InnoDB存储引擎会去读取行的一个快照数据
快照数据其实是当前行数据之前的历史版本,可能有多个版本,一个行可能有不止一个快照数据,我们称这种技术为行多版本技术,由此带来的并发控制,称为多版本并发控制(MVCC)。
在Read Committed的事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。
在Repeatable Read的事务隔离级别(InnoDB的默认隔离级别)下,则总是读取事务开始时的行数据版本。
2、SELECT…FOR UPDATE,SELECT…LOCK IN SHARE MODE
InnoDB对SELECT支持两种锁定:
SELECT…FOR UPDATE:对读取的行记录加一个排他锁,其他任何锁都会被阻塞
SELECT…LOCK IN SHARE MODE:对读取的行记录加一个共享锁。其他事务可以向锁定的记录加共享锁,但是对于加排他锁,则会阻塞。
对于非一致性读锁定读,即使读取的行已经被使用SELECT…FOR UDPADE,也是可以进行读取的。
3、外键和锁
对于一个外键,如果没有显示地对这个列加索引,InnoDB存储引擎自动对其加一个索引。
对父表的SELECT操作,不是使用一致性非锁定的方式,因为这样会发生数据不一致的问题,因此这时使用的是SELECT…LOCK IN SHARE MODE方式。主动对父表加一个S锁,如果这时父表上已经加了排他锁,那么子表上的操作会阻塞。
4、锁的算法(重点)
InnoDB中有三种行锁的算法:
Record Lock:单个行记录上的锁
Gap Lock:间隙锁,锁定一个范围,但不包括记录本身
Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身。
实验:演示Next-Key Lock算法:
1)建立表:
2)插入数据
这里插入了6条数据。
3)打开两个会话:A(左)和B
可看到会话B阻塞住了,因为这是使用的Next-Key Lock算法下,锁定的是(-无穷, 8)数值区间的所有数值。但是插入9是可以的,因为9不在这个范围,对于单值得索引查询,不需要Gap Lock,只需要加一个Record Lock即可。
注意:InnoDB在REPEATABLE READ模式下,Next-Key Lock是默认的行记录锁定算法
5、锁问题
1)丢失更新:多用户计算机系统中,各个用户将远程数据库服务器中的同一行数据读到本地内存中,当各个用户在本地更新并提交数据库后,可能会出现有些用户的更新操作丢失的情况
解决办法:需要将事务变成串行操作,而不是并发操作.
2)脏读:首先有两个概念:脏页指在缓冲池中已经修改的页,但还没有刷新到磁盘,即数据库实例内存中的页和磁盘的页中的数据是不一致的。而脏数据是指缓冲池中被修改的数据,并且还没有提交。
脏读指的是在不同事务下,可以读到另外事务未提交的数据,即可读到脏数据。
解决办法:发生脏读的条件是事务的隔离级别为READ UNCOMMITTED。
3)不可重复读:指一个事务内多次读同一个数据,在这个事务还没有结束前,另外事务也访问该同一数据。那么在第一个事务的两次读数据之间,由于第二个事务的更改,第一个事务两次读到的数据可能不一样。
不可重读读和脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的确实是已提交的数据,但违反了数据库事务的一致性要求。不可重复读又称为幻象问题,InnoDB存储引擎使用Next-Key Lock避免不可重复读问题。
6、阻塞
一个事务中的锁需要等待另一个事务中的锁释放它的资源
二、索引、事务
索引
一个较为容易误解的问题是:B+树索引能找到的只是被查找数据行所在的页,然后数据库通过把页读入内存,再在内存中进行查找,最后得到查找的数据。查找方式一般为二分查找。
索引的使用:
1、对高选择性字段并从表中取出很少一部分行时,对这个字段添加B+树索引是非常必要的;
2、对于联合索引,对联合字段的查找,然而此时若对非第一列进行查找,效率较低,因为B+树中以联合字段的形式进行排序;可以对第二字段进行排序,这样可避免再一次的排序。
事务:
InnoDB存储引擎的事务完全符合ACID(原子性、一致性、隔离性、持久性)
日志的实现主要靠redo(重做)、undo记录
1、事务控制语句:
Ø START TRANSACTION | BEGIN
Ø COMMIT
Ø ROLLBACK
Ø SAVEPOINT identifier
Ø RELEASE SAVEPOINT identifier
Ø ROLLBACK TO [SAVEPOINT] identifier
Ø SET TRACSACTION
2、隐式提交的SQL语句
Ø DDL语句
Ø 用来隐式地修改mysql架构的操作
Ø 管理语句
3、事务隔离级别
Ø READ UNCOMMITEED:读不可提交,在另一个事务没有提交的情况下,也能读取,可能会出现脏读情况
Ø READ COMMITTED:不可重复读,在事务还未提交的情况下,另一事务改变一个数据并提交后,本事务在未提交的情况下能读取变更后的数据。这种情况就是幻读。所以该种隔离级别会出现幻读现象。
Ø REPEATABLE READ:可重复读,可避免脏读以及幻读现象,在本事务未提交的情况下不会读到不同的数据。
Ø SERIALIZATION:序列化,没有并发,虽能避免脏读、幻读等情况,但性能较低
4、不好的事务习惯
1)在循环中提交;
2)使用自动提交;
3)使用自动回滚。