Mysql常用引擎有MYISAM和InnoDB,而InnoDB是mysql默认的引擎。MYISAM只支持表锁,不支持行锁;InnoDB支持行锁和表锁。
行锁和表锁
表锁:开销小,加锁快,不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低。
行锁:开销大,加锁慢,会出现死锁;锁定力度小,锁冲突概率小,处理并发的能力强。
锁冲突:例如说事务A将某个表上锁后,事务B又对其上锁,锁不能共存否则会出现锁冲突。(但是共享锁可以共存,共享锁和排它锁不能共存,排它锁和排他锁也不可以)
死锁:例如说两个事务,事务A锁住了1~5行,同时事务B锁住了6~10行,此时事务A请求锁住6~10行,就会阻塞直到事务B施放6~10行的锁,而随后事务B又请求锁住1~5行,事务B也阻塞直到事务A释放1~5行的锁。死锁发生时,会产生Deadlock错误。(因为表锁是对表操作的,所以自然锁住全表的表锁就不会出现死锁)
表锁
表锁有两种模式:表共享读锁(Table Read Lock) 和 表独占写锁(Table Write Lock)
表共享锁:当一个事务对某个表上读锁后,允许其他事务对这个表进行读操作,但不允许其进行写操作,也不允许其他事务给这个表上排它锁,但允许上共享锁。
表独占写锁:当一个事务对某个表上写锁时,不允许其他事务写,但允许读。更不允许其他事务给这个表上任何锁。包括排它锁。
如何加表锁:
LOCK tables tbl_name read; #加共享锁SELECT * FROM orders WHERE ...;UNLOCK tables; #解锁LOCK tables tbl_name write; #加排它锁UPDATE orders SET ... WHERE ...;UNLOCK tables; #解锁
案例扩展:例如,有一个订单表orders,其中记录有订单的总金额total,同时还有一个订单明细表order_detail,其中记录有订单每一产品的金额小计subtotal,假设我们需要检查这两个表的金额合计是否相等,可能就需要执行如下两条SQL:
SELECT SUM(total) FROM orders;SELECT SUM(subtotal) FROM order_detail;
这时,如果不先给这两个表加锁,就可能会产生错误,因为第一条语句执行过程中,order_detail表可能已经发生了改变。因此,正确的方法应该是:
LOCK tables orders read local,order_detail read local; #加锁SELECT SUM(total) FROM orders;SELECT SUM(subtotal) FROM order_detail;Unlock tables; #解锁
上面的例子在LOCK TABLES时加了local选项,其作用就是在满足表并发插入条件的情况下,允许其他用户在表尾插入记录。
行锁
行锁分 共享锁 和 排它锁。
共享锁:又称读锁。当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排它锁,但允许上读锁。
排它锁:又称写锁。当一个事务对某几个上写锁时,不允许其他事务写,但允许读。更不允许其他事务给这几行上任何锁。包括写锁。
上共享锁的写法:lock in share mode
select math from zje where math>60 lock in share mode;
上排它锁的写法:for update
select math from zje where math >60 for update;
加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;
InnoDB和MyISAM的最大不同点有两个:一,InnoDB支持事务(transaction);二,默认采用行级锁。加锁可以保证事务的一致性,可谓是有人(锁)的地方,就有江湖(事务);
另外,可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:
mysql> show status like 'innodb_row_lock%';+-------------------------------+-------+| Variable_name | Value |+-------------------------------+-------+| Innodb_row_lock_current_waits | 0 || Innodb_row_lock_time | 0 || Innodb_row_lock_time_avg | 0 || Innodb_row_lock_time_max | 0 || Innodb_row_lock_waits | 0 |+-------------------------------+-------+5 rows in set (0.00 sec)
如果发现争用比较严重,如Innodb_row_lock_waits和Innodb_row_lock_time_avg的值比较高,还可以通过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析锁争用的原因。
参考信息:
https://www.cnblogs.com/lsxuejava/p/7305920.html
https://blog.csdn.net/u014453898/article/details/56068841
