MYSQL的锁

MYSQL的锁,第1张

MYSQL的锁

 锁的分类:

    按表粒度划分:表锁、行锁、页锁;按加锁机制划分:乐观锁、悲观锁;按兼容性划分:共享锁、排他锁;按可见性划分:显式锁、隐式锁;按锁模式划分:记录锁、gap锁、next-key锁、意向锁、插入意向锁。
按表粒度分:

1、表级锁:开销小,加锁快,不会出现死锁,锁粒度大(整张表),并发度低,发生锁竞争概率大,适合查询。

2、行级锁:开销大,加锁慢,会出现死锁,锁粒度最小(一行数据),并发度高,发生锁竞争概率小,适合并发写,事务控制。

3、页面锁:开销、加锁速度、锁粒度、并发度都介于表级锁和行级锁之间,会出现死锁。

很难说那种锁更好,只能说就具体应用程序的特点说哪种锁更合适。对于查询 *** 作远大于修改、插入 *** 作的表而言,采用表级锁更加合适。行级锁更加适合有大量按索引条件查询并发更新少量不同数据,同时又有并发查询的应用。

行级锁注意事项:并不是直接丢记录行加锁,而是对行对应的索引加锁:

    如果sql 语句 *** 作了主键索引,Mysql 就会锁定这条主键索引。如果sql语句 *** 作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。在InnoDB中,如果SQL语句不涉及索引,则会通过隐藏的聚簇索引来对记录加锁。对聚簇索引加锁,实际效果跟表锁一样,因为找到某一条记录就得扫描全表,要扫描全表,就得锁定表。
按加锁机制分【逻辑上的锁】

悲观锁思想就是,当前线程要进来修改数据时,别的线程都得拒之门外,悲观锁认为并发问题极易发生,所以每次 *** 作,无论读写,都会对记录加锁,以防止其他线程对数据进行修改。实现方式:数据库的行锁、读锁和写锁。

~ 比如,可以使用select…for update ~

select * from User where name=‘jay’ for update
复制代码

【悲观锁是行锁还是表锁?没用索引/主键的话就是表锁,否则就是是行锁。】

以上这条sql语句会锁定了User表中所有符合检索条件(name=‘jay’)的记录。本次事务提交之前,别的线程都无法修改这些记录。

乐观锁思想就是,有线程过来,先放过去修改,如果看到别的线程没修改过,就可以修改成功,如果别的线程修改过,就修改失败或者重试。

乐观锁虽然认为并发问题很难发生,但并不是不会发生,所以也会有措施防止问题真的产生:每次数据修改都自增版本号version。
进行数据读取时,并不加锁,而是同时读取当前的版本号version1;在对数据进行修改时,要判断当前的版本号version2是否等于之前的版本号version1。
版本号不匹配,则代表着并发问题已产生,所以需要回滚此次 *** 作。

实现方式:乐观锁一般会使用版本号机制或CAS算法实现。

按兼容性分

共享锁

又称之为S锁、读锁。
当前线程对共享资源加共享锁,其他线程可以读取此资源、可以继续追加共享锁,但是不能修改此资源、不能追加排他锁。
语法:select id from t_table in share mode;
多个共享锁可以共存,共享锁与排他锁不能共存。

排他锁

又称之为X锁、写锁。
当前线程对共享资源加排他锁,其他线程不允许读取此资源,不允许追加共享锁,不允许修改此资源,不允许追加排他锁。
语法:
update t_table set a =1; // 数据库的增删改 *** 作默认都会加排他锁
select * from t_table for update;// for update也是一种增删改
排他锁是独占的,不会与其他锁共存。

按可见性划分

隐式锁

InnoDB会根据隔离级别在需要的时候自动加锁,这称为隐式加锁,

InnoDB采用两阶段锁定协议,在事务执行过程中,随时都可以执行锁定,锁只有在执行commit或rollback的时候才会释放,并且所有的锁是在同一时刻被释放的,这就是隐式锁定,InnoDB会根据事务的隔离级别在需要的时候自动加锁。

显示锁

显示加共享锁:

select  ....  lock in share mode

显示加排它锁

select  ....  for update

注意:按照不同维度划分的锁,相互之间没有任何联系,例如悲观锁可以是行锁也可以是表锁

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5719693.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存