1  概述

【为什么要锁】

当并发事务同时访问一个资源时,有可能导致数据不一致,因此需要一种机制来将数据访问顺序化,以保证数据库数据的一致性。锁就是其中的一种机制。

数据库是一个多用户使用的共享资源,比如一个用户表t_user,两个浏览器前面的人登录了同个一个账号,把电话号码改了。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性(脏读,不可重复读,幻读等),可能产生死锁。为了解决这个问题,加锁是一个非常重要的技术,对实现数据库并发控制是一个好的方案。简单说,当一个执行sql语句的事务想要操作表记录之前,先向数据库发出请求,对你访问的记录集加锁,在这个事务释放这个锁之前,其他事务不能对这些数据进行更新操作。

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。下面举例说明并发操作带来的数据不一致性问题:

现有两处火车票售票点,同时读取某一趟列车车票数据库中车票余额为 X。两处售票点同时卖出一张车票,同时修改余额为 X -1写回数据库,这样就造成了实际卖出两张火车票而数据库中的记录却只少了一张。 产生这种情况的原因是因为两个事务读入同一数据并同时修改,其中一个事务提交的结果破坏了另一个事务提交的结果,导致其数据的修改被丢失,破坏了事务的隔离性。并发控制要解决的就是这类问题。

封锁、时间戳、乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

2  概念介绍

锁类型 :

读锁:共享锁,可被多个读操作共享;只能共享给读。

写锁:排它锁,独占锁;

锁粒度:

表锁:在表级别施加锁,并发性较低;表级锁的粒度大于行级锁

行锁:在行级别施加锁,并发性较高;维持锁状态的成本较大;

锁的粒度越小,可能会造成死锁的状态。如两行需要同时编辑的时候,互相需要等待另一行解锁,造成了死锁的情况。

锁策略:在锁粒度及数据安全性之间寻求一种平衡机制;使得并发机制正常,同时又能维持正常的锁状态。

存储引擎级别的锁:级别以及何时施加或释放锁由存储引擎自行决定;由引擎决定

MySQL Server:表级别,可自行决定,也允许显式请求;允许用户手动请求和施加锁,是表级别的。

锁类别:

显式锁:用户手动请求的锁;

隐式锁:存储引擎自行根据需要施加的锁;

3  显式锁的使用

(1) LOCK TABLES 

LOCK TABLES  tbl_name  read|write, tbl_name read|write, ...

UNLOCK TABLES #解开全部的锁,后面不跟表名

施加写锁,写锁是排他的,不允许别的线程读和写,自己施加锁是不受影响

 lock tables classlist write;

MariaDB [sunny]> lock tables classlist write;

Query OK, 0 rows affected (0.00 sec)

MariaDB [sunny]> select * from classlist; #此时是可以正常读写

Empty set (0.00 sec)

注意,此时当另一用户连接的时候(从另一终端登录该数据库),查看的时候,结果就出不来,处于锁住的状态。

MariaDB [sunny]> select * from classlist;

施加读锁后,别的进程可以看,但是不能插入数据,读锁对写锁排斥,解锁后才能正常

MariaDB [sunny]> lock tables classlist read;

Query OK, 0 rows affected (0.00 sec)

此时从另一终端登录插入数据时是处于锁住状态

MariaDB [sunny]> insert into classlist values ("sunny",1,"100");

(2) FLUSH TABLES:将内存中的数据同步到磁盘上,即刷写操作,但是这个同步过程可以施加锁,一旦施加锁的时候,即执行将对应的表同步,关闭,打开,并施加锁。一旦施加了锁,此时别的线程读操作不受影响,但是写操作将不能被执行,需要解锁后才能生效

FLUSH TABLES tbl_name,... [WITH READ LOCK];

UNLOCK TABLES;

锁住所有的表,注意,可以针对某张表进行上锁

MariaDB [sunny]> flush tables with read lock;

Query OK, 0 rows affected (0.00 sec)

其他线程,解锁后才能够插入数据

MariaDB [sunny]> insert into classlist values ("tracy",2,"99");

Query OK, 1 row affected (1 min 5.58 sec)

(3) SELECT cluase #FOR UPDATE请求施加写锁,LOCK IN SHARE MODE施加读锁,一般不操作

[FOR UPDATE | LOCK IN SHARE MODE]

一般要操作的是手动解锁。但是可能会对已经在软件层的操作造成影响。

更多介绍建议参考链接:

数据库的锁机制:http://blog.csdn.net/lexang1/article/details/52248686

数据库为什么需要锁机制?有哪些锁机制?:https://www.cnblogs.com/fanp/p/4633453.html