最近在努力研究关于数据库相关的知识,正好研究到了Mysql InnoDB锁相关的内容,所以特意写下此文,与各位分享我的知识,如有错误,麻烦与我一起探讨,谢谢。
锁是什么?
在业务运行过程中,可能会有很多用户同时操作数据库同一个数据,这个时候就需要有一种机制来保证数据的写入和存储是安全的,这个时候锁就诞生了,锁顾名思义,可以帮助我们锁住某些内容,防止一个用户在修改的过程中被另外的用户修改,导致前后数据不一致。
如何验证锁?
在写文过程中,只是单纯的讲概念,贴文字简直就是太枯燥了,所以在全文我会使用Navicat来展示我的发现。navicat如何查看Mysql数据库线程:使用【show processlist】命令查看,该命令可以查看用户正在运行的线程,如果是root用户,可以看所有正在运行的线程,如果是其他用户,则只能看到自己正在运行的线程show processlist命令显示结果navicat中每新增加一个查询窗口就相当于开启了一个线程,这对于我们伪造两个事务一个先执行更新操作但是不提交,然后另外一个线程接着来更新同一行,看锁怎么处理提供了方便。navicat每新增一个查询框口,都会增加线程
锁的分类:
按锁的颗粒度分:全局锁
使用场景:全库逻辑备份
定义:对整个数据库进行加锁,导致数据库没办法增删改,只能读
使用方法:使用【flush tables with read lock】命令即可锁住整个库执行全局锁命令后,执行更新操作将会被阻塞执行了全局锁命令后再去执行增删改操作都会被阻塞表锁
表锁
使用场景:需要限制本线程和其他线程操作的时候。比如说1号线程上了读锁,其他线程都只能阻塞
定义:该锁需要执行命令才会给表加上读锁或者写锁
使用方法:使用【lock tables … read/write】即可锁住对应的表,可以上读锁,也可以上写锁表加了读锁后将会阻塞其他写操作元数据锁
使用场景:当执行增删改查操作时,会自动加上元数据读锁;当执行修改表结构的时候,会自动加上元数据写锁;是为了保证表结构的一致性
定义:在执行操作的时候,会自动给表加锁,该锁为元数据锁,是为了保证表结构一致性而出现的
使用方法:不需要显式调用,该机制由mysql自身保证
行锁
使用场景:在并发操作时,多个线程需要对同一行进行增删改查,需要有一把锁控制有序修改
定义:对某一行进行加锁,锁住后其他线程不能操作当前线程
方法:有悲观锁【select * from tables for update】和乐观锁【由用户自行控制,操作前查询版本号,修改后对比前后版本号,符合版本更新原则即更新完成】两种,都是需要用户自行控制
行锁的具体分析:因为行锁是InnoDB引擎默认使用的锁方式,但是会在使用过程中因为使用不当,会升级成表锁,所以这一块需要单独拿出来分析一下
行锁和表锁区别:
行锁开销大,加锁慢(因为操作级别很细,需要具体到某一行),锁定颗粒度小,发生锁冲突的概率小,并发度高
表锁开销小,枷锁快,锁定颗粒度大,发生锁冲突概率大,并发度低
应用场景:InnoDB是通过给索引上的索引加锁来实现的,也就意味着使用了索引条件来检索数据使用的是行锁,反之则会升级成为表锁
使用主键作为查询条件去修改某一数据使用的是行锁如何查看行锁使用非索引字段作为条件去修改某一数据使用的是表锁,此处后续再进行更新
按加锁机制分:乐观锁:针对每一次操作,都乐观的认为不会发生锁碰撞,一般做法是首先查询出目前数据库记录数据的版本后,然后再去更新,更新后再查询版本号是否按照预期增长,如果没有按照预期增长,则直接回滚事务
悲观锁:针对每一次操作,都悲观的认为会发生碰撞,所以在操作之前就去获取锁,获取到了再进行操作,反之则进行等待
按兼容性分:共享锁:又称之为读锁,也称S锁。即针对多个事务可以同时来读取相同数据,但是不能修改
排他锁:又称之为写锁,也称X锁。获取写锁后,将会阻碍其他线程读取或者更新