ホームページ >データベース >mysql チュートリアル >Mysql のロックについて詳しく学び、使用シナリオについて話しましょう。

Mysql のロックについて詳しく学び、使用シナリオについて話しましょう。

青灯夜游
青灯夜游転載
2022-06-28 20:55:492132ブラウズ

この記事では、Mysql のロックについて説明し、共有ロック、排他的ロック、悲観的ロック、楽観的ロックを理解し、使用シナリオについて説明します。

Mysql のロックについて詳しく学び、使用シナリオについて話しましょう。

#1. 一般的なロック タイプ

    テーブル レベルのロック、テーブル全体をロックする
  • ページ レベル ロック、ページをロックします。
  • 行レベル ロック、行をロックします。
  • 共有ロック (S ロックとも呼ばれます)、MyISAM では読み取りロックとも呼ばれます
  • 排他ロック、 X ロックとも呼ばれ、MyISAM では書き込みロックとも呼ばれます
  • 悲観的なロック、抽象的な性質は実際には存在しません
  • 楽観的なロック、抽象的な性質は実際には存在しません


一般的なロック タイプ

2. Mysql エンジンの概要

    実際、mysql には多くの種類のエンジンがありますが、その中で InnoDB エンジンと MyISAM エンジンが最もよく使用されます
  • mysql5.5 バージョンより前は MyISAM エンジンがデフォルトで使用され、それ以降は InnoDB エンジンが使用されます
  • データベース エンジン コマンドは次のように表示されます
show variables like '%storage_engine%';

3. 一般的に使用されるエンジンの違い

  • #MyISAMは、テーブル ロックを使用してデータを操作します。レコードを更新するときは、テーブル全体をロックする必要があります。その結果、パフォーマンスが低下し、同時実行性が低下します。もちろん、同時にデッドロックの問題も発生しません。

  • InnoDB と MyISAM の最大の違いは 2 点です: 1 つ目は、InnoDB がトランザクションをサポートしていること、2 つ目は、InnoDB が行レベルのロックを使用していることです。

  • Mysql では、行レベルのロックはレコードを直接ロックするのではなく、インデックスをロックします。インデックスは主キー インデックスと非主キー インデックスに分割されます。SQL ステートメントが主キー インデックスで動作する場合、MySQL は主キー インデックスをロックします。ステートメントが非主キー インデックスで動作する場合、MySQL は最初に主キー インデックスをロックします。非主キー インデックスを削除してロックする 関連する主キー インデックス。

  • InnoDB の行ロックは、インデックス エントリをロックすることによって実装されます。インデックスがない場合、InnoDB は非表示のクラスター化インデックスを通じてレコードをロックします。言い換えると、インデックス条件を通じてデータを取得しない場合、InnoDB はテーブル内のすべてのデータをロックし、実際の効果はテーブル ロックと同じになります。インデックスがないため、特定のレコードを見つけるにはテーブル全体をスキャンする必要があります。テーブル全体をスキャンするには、テーブルをロックする必要があります。

4. 共有ロックと排他ロック

  • データベースの追加、削除、変更操作により、排他ロックが追加されます。デフォルトではロックが設定されており、クエリ「No locks」が追加されます。

  • 共有ロック: 特定のリソースに共有ロックを追加すると、あなたはそのリソースを読み取ることができ、他の人もそのリソースを読み取ることができます (追加を続けることもできます)共有ロック (つまり、複数の共有ロックが共存できます) ですが、変更することはできません。これを変更する場合は、すべての共有ロックが解除されるまで待つ必要があります。

  • 排他ロック: 特定のリソースに排他ロックを追加します。自分自身は追加、削除、変更、確認できますが、他の人は何も操作できません。

//共享锁
select * from 表名 lock in share mode

//排他锁
select * from 表名 for update

五、排他锁的实际应用

  • 这里我们以两个操作数据库的请求为例,假设这两个请求分别为T1和T2
  • 假设T1为查询请求,而T2为更新数据请求,在T1查询很长时间的时候,还没有返回结果,但是这时候T2过来请求更新了
  • 这个流程应该是: T1运行加共享锁、T2运行、发现T1未完成等待其完成、T1完成、T2开始执行
  • T2之所以要等待,是因为T2执行更新的时候需要给表加排他锁,但是数据库规定,不能在同一资源上同时共存这两种锁,所以T2必须等T1执行完,释放锁后,才可以正常操作
T1: select * from 表名 lock in share mode //假设还未返回结果

T2: update 表名 set name='autofelix'

六、共享锁的实际应用

  • 如果T1和T2都是执行的查询,也就是都加共享锁
  • 这时候就不用等待,可以立马执行
  • 因为同一资源上可以同时存在多个共享锁,也被称为,共享锁与共享锁兼容
  • 意味着共享锁不阻止其他人同时读取资源,但是阻止其他人修改资源
T1: select * from table lock in share mode

T2: select * from table lock in share mode

七、死锁的发生

  • 假设T1和T2都同时执行2个资源操作,分别是查询和更新数据
  • 假设T1和T2同时达到select,T1对表加共享锁,而T2也加上了共享锁
  • 当T1的select执行完毕,准备执行update时
  • 根据锁机制,T1的共享锁必须升级到排他锁才可以执行接下来的update操作
  • 在升级排他锁之前,必须等T2的共享锁释放,同理,T2也在等T1的共享锁释放
  • 于是都在等待对方的锁释放,导致程序卡死,这种情况就是死锁
T1: 开启事务,执行查询更新两个操作

     select * from table lock in share mode

     update table set column1='hello'

T2: 开启事务,执行查询更新两个操作

     select * from table lock in share mode

     update table set column1='world'

八、另一种发生死锁的情景

  •  当T1和T2都是只执行更新语句的时候
  • 如下程序所示,这种语句非常的常见,很多人觉得他会产生死锁,其实要看情况
  • 如果id是主键,由于主键机制,并不需要全表扫描,直接可以更新当前数据,所以不会产生死锁
  • 如果id是普通字段,那么当T1加上排他锁之后,T2为了找到id=20条数据,必须进行全表扫描,当他扫到第10条的时候,发现这里有排他锁,导致全表扫描进行不下去,就会导致等待
T1: begin
     update table set content='hello' where id=10

T2: begin
     update table set content='world' where id=20

九、死锁的解决方式

  • 就是让T1和T2顺序执行,比如T1在执行完select后,立马给自身加上排他锁,这样T2不得不等待T1执行完才能继续
  • 但是如果有很多请求过来的话,都必须等待,这对用户特别的不友好
  • 所以,某些数据库引入了另一种方式,叫做更新锁,这里mysql除外,不存在更新锁
  • 更新锁其实就是排他锁的另一种实现,只是他允许其他人读的同时加共享锁,但是不允许其他操作,除非释放了更新锁
  • 流程大概如此: T1执行完select加上更新锁,T2执行查询完,准备加更新锁,发现已经有了,就等待,其他请求过来,如果查询是不受影响的,但是更新才等待
  • 这相比上面的查询也要等待增加了效率
T1: begin

     select * from table for update

     update table set content='hello'

T2: begin

     select * from table for update

     update table set content='world'
T1: begin

     select * from table [加更新锁操作]

     update table set content='hello'

T2: begin

     select * from table [加更新锁操作]

     update table set content='world'

十、意向锁和计划锁

  • 计划锁与程序猿无关,不需要了解
  • 意向锁,Innodb特有,分为意向共享锁和意向排他锁
  • 意向共享锁: 表示事务获取共享锁时,必须先得获取该表的意向共享锁
  • 意向排他锁: 表示事务获取排他锁时,必须先得获取该表的意向排他锁
  • 我们知道要对整个表加锁,必须保证表内不存在任何锁
  • 如果一行行的去检查是否加锁,效率必然极低,这时候可以检测意向锁是否被占用即可

十一、乐观锁和悲观锁

  • 乐观锁和悲观锁都是针对select而言的
  • 比如在商品抢购中,用户购买后库存需要减1,而很多用户同时购买时,读出来的库存数量一样,然后多个用户同时用该库存去减1
  • 这种做法必然会出现很大的漏洞,如果向在淘宝,京东出现这种情况,你就可以打包回家种地了
  • 这种情况如何解决呢,其实可以使用悲观锁进行解决,说白了也就是排他锁
  • 用户进来查库存的时候,就加上排他锁,等他所有操作完成后,再释放排他锁,让其他人进来
  • 不让用户等待,就可以使用乐观锁方式解决,乐观锁一般靠表的设计和时间戳来实现
  • 一般是在表中添加version或者timestamp时间戳字段
  • 这样就会保证如果更新失败,就表示有其他程序更新了数据库,就可以通过重试解决
update table set num=num-1 where id=10 and version=12

【相关推荐:mysql视频教程

以上がMysql のロックについて詳しく学び、使用シナリオについて話しましょう。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。