ホームページ >データベース >mysql チュートリアル >デッドロックとは何ですか? MySQL デッドロックについての理解を話しましょう
デッドロックとは何ですか?次の記事では、MySQL デッドロックについて説明します。 MySQL でデッドロックが発生するために必要な条件と、デッドロックの問題を解決する方法について話しましょう。お役に立てれば幸いです。
デッドロックとは、2 つ以上の異なるプロセスまたはスレッドにおいて、共通リソースの競合またはプロセス (またはスレッド) 間の通信により各スレッドがブロックされている状況を指します。外力がなければ、最終的にはシステム全体が崩壊してしまいます。
# は、同じリソースをめぐって競合する場合の複数のトランザクションの相互排他性を指します。つまり、リソースは一定期間内に 1 つのトランザクションによってのみ占有されます。これは排他的リソース (行ロックなど) とも呼ばれます。
ロック A はトランザクション a で取得されましたが、新しいロックが取得されたことを意味しますB が要求され、ロック B は別のトランザクション b によってすでに占有されています。このとき、トランザクション a はブロックされますが、取得したロック A は保持されます。
#相互ロック取得条件
3. Mysql の古典的なデッドロック ケース
#3.1 テーブル作成文
CREATE TABLE `account` (
`id` int(11) NOT NULL COMMENT '主键',
`user_id` varchar(56) NOT NULL COMMENT '用户id',
`balance` float(10,2) DEFAULT NULL COMMENT '余额',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账户余额表';
#3.2 関連データの初期化
INSERT INTO `test`.`account` (`id`, `user_id`, `balance`) VALUES (1, 'A', 80.00); INSERT INTO `test`.`account` (`id`, `user_id`, `balance`) VALUES (2, 'B', 60.00);
3.3 通常の転送プロセス
デッドロックの問題について説明する前に、見てみましょう。まずは通常の転送プロセスを参照してください。 通常の状況では、ユーザー A がユーザー B に 50 元を送金します。これは 1 回の取引で完了します。最初にユーザー A の残高とユーザー B の残高を取得する必要があります。これら 2 つのデータは後で変更する必要があるため、書き込みロックが必要です (UPDATE の場合) 他のトランザクションの変更によって変更が失われてデータがダーティになるのを防ぐためにロックします。 関連する SQL は次のとおりです:
#Q1NETiBA6ZqQIOmjjg==, size_20,color_FFFFFF,t_70,g_se,x_16)トランザクションを開始する前に、mysql の自動送信をオフにする必要があります
set autocommit=0; # 查看事务自动提交状态状态
show VARIABLES like 'autocommit' ; * 事务2入参(B, A) **/ public void transferAccounts(String userFrom, String userTo) { // 获取分布式锁 Lock lock = Redisson.getLock(); // 开启事务 JDBC.excute("START TRANSACTION;"); // 执行转账sql JDBC.excute("# 获取A 的余额并存入A_balance变量:80\n" + "SELECT user_id,@A_balance:=balance from account where user_id = '" + userFrom + "' for UPDATE;\n" + "# 获取B 的余额并存入B_balance变量:60\n" + "SELECT user_id,@B_balance:=balance from account where user_id = '" + userTo + "' for UPDATE;\n" + "\n" + "# 修改A 的余额\n" + "UPDATE account set balance = @A_balance - 50 where user_id = '" + userFrom + "';\n" + "# 修改B 的余额\n" + "UPDATE account set balance = @B_balance + 50 where user_id = '" + userTo + "';\n"); // 提交事务 JDBC.excute("COMMIT;"); // 释放锁 lock.unLock(); }
上面的伪代码显而易见可以解决死锁问题,因为所有的事务都是通过分布式锁来串行执行的。
那么这样就真的万事大吉了吗?
在小流量情况下看起来是没问题的,但是在高并发场景下这里将成为整个服务的性能瓶颈,因为即使你部署了再多的机器,但由于分布式锁的原因,你的业务也只能串行进行,服务性能并不因为集群部署而提高并发量,完全无法满足分布式业务下快、准、稳的要求,所以咱们不妨换种方式来看看怎么解决死锁问题。
4.2 打破相互获取锁条件(推荐)
要打破这个条件其实也很简单,那就是事务再获取锁的过程中保证顺序获取即可,也就是锁A始终在锁B之前获取。
我们来看看之前的伪代码怎么优化?
/** * 事务1入参(A, B) * 事务2入参(B, A) **/ public void transferAccounts(String userFrom, String userTo) { // 对用户A和B进行排序,让userFrom始终为用户A,userTo始终为用户B if (userFrom.hashCode() > userTo.hashCode()) { String tmp = userFrom; userFrom = userTo; userTo = tmp; } // 开启事务 JDBC.excute("START TRANSACTION;"); // 执行转账sql JDBC.excute("# 获取A 的余额并存入A_balance变量:80\n" + "SELECT user_id,@A_balance:=balance from account where user_id = '" + userFrom + "' for UPDATE;\n" + "# 获取B 的余额并存入B_balance变量:60\n" + "SELECT user_id,@B_balance:=balance from account where user_id = '" + userTo + "' for UPDATE;\n" + "\n" + "# 修改A 的余额\n" + "UPDATE account set balance = @A_balance - 50 where user_id = '" + userFrom + "';\n" + "# 修改B 的余额\n" + "UPDATE account set balance = @B_balance + 50 where user_id = '" + userTo + "';\n"); // 提交事务 JDBC.excute("COMMIT;"); }
假设事务1的入参为(A, B),事务2入参为(B, A),由于我们对两个用户参数进行了排序,所以在事务1中需要先获取锁A在获取锁B,事务2也是一样要先获取锁A在获取锁B,两个事务都是顺序获取锁,所以也就打破了相互获取锁的条件,最终完美解决死锁问题。
因为mysql在互联网中的大量使用,所以死锁问题还是经常会被问到,希望兄弟们能掌握这方面的知识,提高自己的竞争力。
【相关推荐:mysql视频教程】
以上がデッドロックとは何ですか? MySQL デッドロックについての理解を話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。