前面两篇博客中简单的聊了下mysql中的索引,今天聊聊mysql(InnoDB引擎)中的锁以及事务的实现
MySQL(二) MySql经常使用优化
mysql
讲到锁你们应该都不陌生。像是Java中常见的采用CAS算法实现的乐观锁,典型的例子就是原子类,经过CAS自旋实现原子操做的更新,悲观锁一般都是Synchronized
和Lock
实现。
# 加上lock in share mode
SELECT description FROM book_book lock in share mode;复制代码
# 加上for update
SELECT description FROM book_book for update;
复制代码
行锁与表锁区别在于锁的粒度,在Innodb引擎中既支持行锁也支持表锁(MyISAM引擎只支持表锁),只有经过索引条件检索数据InnoDB才使用行级锁,不然,InnoDB将使用表锁。
这里有个比较疑惑的地方,为何表锁不会出现死锁?在MyISAM中因为没有事务,一条SQL执行完锁就释放了,不会循环等待,因此只会出现阻塞而不会发生死锁。可是在InnoDB中有事务就比较疑惑了,但愿有了解的小伙伴指点指点@-@算法
下面举两个例子说明上面几种锁:
# 事务1
BEGIN;
SELECT description FROM book_book where name = 'JAVA编程思想' lock in share mode;
# 事务2
BEGIN;
UPDATE book_book SET name = 'new book' WHERE name = 'new';
# 查看事务状态
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
trx_id trx_state trx_started trx_tables_locked trx_rows_locked
39452 LOCK WAIT 2018-09-08 19:01:39 1 1
282907511143936 RUNNING 2018-09-08 18:58:47 1 38
复制代码
事务1给book表加上了共享锁,事务2尝试修改book表发生了阻塞,查看事务状态能够知道事务一因为没有走索引使用了表锁。
sql
# 事务1
BEGIN;
SELECT description FROM book_book WHERE id = 2 lock in share mode;
# 事务2
BEGIN;
UPDATE book_book SET name = 'new book' WHERE id = 1;
# 查看事务状态
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
trx_id trx_state trx_started trx_tables_locked trx_rows_locked
39454 RUNNING 2018-09-08 19:10:44 1 1
282907511143936 RUNNING 2018-09-08 19:10:35 1 1
复制代码
事务1给book表加上了共享锁,事务2尝试修改book表并无发生阻塞。这是因为事务一和事务二都走了索引,因此使用的是行锁,并不会发生阻塞。
数据库
意向锁的意义在于方便检测表锁和行锁之间的冲突
IX IS X S
IX 兼容 兼容 冲突 冲突
IS 兼容 兼容 冲突 兼容
X 冲突 冲突 冲突 冲突
S 冲突 兼容 冲突 兼容
复制代码
MVCC使得InnoDB更好的实现事务隔离级别中的REPEATABLE READ
间隙锁使得InnoDB解决幻读问题,加上MVCC使得InnoDB的RR隔离级别实现了串行化级别的效果,而且保留了比较好的并发性能。
定义:当咱们用范围条件检索数据时请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引加锁;对于键值在条件范围内但并不存在的记录,叫作间隙(GAP),InnoDB也会对这个"间隙"加锁,这种锁机制就是间隙锁。
编程
例如:book表中存在bookId 1-80,90-99的记录。SELECT * FROM book WHERE bookId < 100 FOR UPDATE。InnoDB不只会对bookId值为1-80,90-99的记录加锁,也会对bookId在81-89之间(这些记录并不存在)的间隙加锁。这样就能避免事务隔离级别可重复读下的幻读。bash
有问题的同窗能够指出相互探讨,如需转载请注明出处。
参考文献:
https://dev.mysql.com/doc/refman/5.7/en/innodb-multi-versioning.htmlhttps://www.cnblogs.com/chenpingzhao/p/5065316.html