others linux服务器运维 django3 监控 k8s golang 数据库 大数据 前端 devops 理论基础 java oracle 运维日志

mysql 锁机制和实践

访问量:1396 创建时间:2021-04-21

锁分类

从操作的粒度可以分为表级锁,行级锁和页级锁。

表级锁: 每次操作锁住整张表。锁定粒度大,发生所冲突的概率最高,并发度最低。应用在MyISAM、Innodb、BDB等存储引擎中。 行级锁: 每次操作锁住一行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在Innodb存储引擎中。 页级锁: 每次锁定相邻的一组记录,锁定粒度界于表锁和行锁之间,开销和加锁时间界于表锁和行锁之间,并发度一般。应用在BDB存储引擎中。

从操作类型可以分为读锁和写锁

从操作的性能可以分为乐观锁和悲观锁

乐观锁:一般的实现方式是对记录数据版本进行比较,在数据更新提交的时候才会进行冲突检测,如果发现冲突了,则提示错误信息。 悲观锁: 在对一条数据修改的时候,为了避免同时被其他人修改,在修改数据之前先锁定,再修改的控制方式。共享锁和排他锁是悲观锁的不同实现,但都属于悲观锁范畴。

行锁原理

悲观锁

共享锁(行级锁-读锁): 共享锁又称为读锁,简称S锁。共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。使用共享锁的方法是select ... lock in share mode ,只适用查询语句。事务使用了共享锁(读锁),只能读取,不能修改,修改操作被阻塞。

排它锁(行级锁-写锁):排它锁又称写锁,简称x锁。排它锁就是不能与其他锁并存,如果一个事物获取了一个数据行的排它锁,其他事物就不能对该行记录做其他操作,也不能获取改行的锁。使用排它锁的方法是在SQL末尾加上for update,innodb引擎默认会在update,delete语句上加上for update.行级锁的实现其实是依靠其对应的索引,所以如果操作没用到索引的查询,那么会锁住全表记录。总结:事务使用了排它锁(写锁),当前事物可以读取和修改,其他事物不能修改,也不能获取记录锁(select ... for update). 如果查询没有使用到索引,将会锁住整个表记录。

乐观锁

乐观锁是相对于悲观锁,它不是数据库提供的功能,需要开发者自己去实现。在数据库操作时,想法很乐观,认为这次的操作不会导致冲突,因此在数据库操作时并不做任何的特殊处理,既不加锁,而是在进行事务提交时再去判断是否有冲突了。

乐观锁实现的关键点:冲突的检测。

悲观锁和乐观锁都可以解决事务写写并发,在应用中可以根据并发能力选择区分,比如对并发率要求较高的选择乐观锁;对于并发率要求较低的可以选择悲观锁。

实现原理:

使用时间戳(timestamp):与使用version版本字段相似,同样需要给在数据库表增加一个字段,字段类型使用timestamp时间戳。也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则提交更新,否则就是版本冲突,取消操作。

死锁和处理方法

产生原因2: 两个事务分别想拿到对方持有的锁,互相等待,于是产生死锁。 解决方法:在同一个事务中,尽可能做到一次锁定所需要的所有资源;按照id对资源排序,然后按顺序进行处理。

登陆评论: 使用GITHUB登陆