MySQL事务与锁机制(下)

833 阅读4分钟

MySQL事务与锁机制(下)

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

前言: 上文讲了mysql的事务特性已经隔离级别MySQL事务与锁机制(上),本篇文章将会讲解下mysql自带的锁机制.

锁在我们程序开发中是经常运用到的一种机制,常见的锁就如有JDK的Lock接口下来一系列锁,snychronized,分布式锁等等,锁是计算机协调多个进程或线程并发访问某一资源的机制,因此在数据库中也存在这种机制。在锁的整体大类中可以分为以下几种:

  • 从性能上分为乐观锁(通过版本号对比来实现)和悲观锁

  • 从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)

  • 读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响

  • 写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁从对数据操作的粒度分,分为表锁和行锁。

表锁

顾名思义,表锁就是锁定整张表,开销小,加锁快;不会出现死锁;锁定粒度大(整张表),发生锁冲突的概率最高,并发度最低

一般用在整表数据迁移的场景。

加锁方式:

  • 手动增加表读写锁:lock table 表名称 read(write),表名称2 read(write);读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。

  • 查看表上加过的锁:show open tables

  • 删除表锁 :unlock tables

行锁

行锁是锁定当前操作行的数据,锁的颗粒度小,处理并发的能力强,锁冲突的概率小,但是开销大,有几率会出现死锁。

加锁方式

自动加锁,InnoDB对于SELECT以外的语句会自动增加加排他锁;对于SELECT语句是不会自动加锁的;当然我们也可以手动的加锁:

  • 共享锁:多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改

加锁语句:select * from tableName where … + lock in share more

  • 排他锁: 排它锁就是同一时间只能有一个数据访问到数据,并且可以对该数据进行修改与读取,但是其他事务无法访问到该数据,知道锁被释放

加锁语句:select * from tableName where … + for update

注意事项

但是我们需要注意一小点,mysql的行锁是建立在索引的机制上,如果where条件上的索引失效的话,那么就会走全表扫描,从而导致行锁变为表锁,全部阻塞

间隙锁(Gap Lock)

间隙锁,锁的就是两个值之间的空隙。Mysql默认级别是repeatable-read,有办法解决幻读问题吗?间隙锁在某些情况下可以解决幻读问题。

首先表里有以下数据

image.png

那么间隙就有 id 为 (3,10),(10,20),(20,正无穷) 这三个区间,在Session_1下面执行 update account set name = 'zhangsan' where id > 8 and id <18;,

则其他Session没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在(3,20]区间都无法修改数据,注意最后那个20也是包含在内的。

间隙锁是在可重复读隔离级别下才会生效。

临键锁(Next-key Locks)

Next-Key Locks是行锁与间隙锁的组合。像上面那个例子里的这个(3,20]的整个区间可以叫做临键锁

结论

Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更 高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb 的整体性能和MYISAM相比就会有比较明显的优势了。