InnoDB数据库死锁问题处理
场景描述
在update表的时候出现DeadlockLoserDataAccessException异常 (Deadlock found when trying to get lock; try restarting transaction...)。
问题分析
这个异常并不会影响用户使用,因为数据库遇到死锁会自动回滚并重试。用户的感觉就是操作稍有卡顿。但是监控老是报异常,所以需要解决一下。
解决方法
在应用程序中update的地方使用try-catch。
我自己封装了一个函数,如下。
<code class="language-java">/** * 2016-03-15 * linxuan * handle deadlock while update table */ private void updateWithDeadLock(TestMapper mapper, Test record) throws InterruptedException { boolean oops; int retries = 5; do{ oops = false; try{ mapper.updateByPrimaryKeySelective(record); } catch (DeadlockLoserDataAccessException dlEx){ oops = true; Thread.sleep((long) (Math.random() * 500)); } finally { } } while(oops == true && retries-- >0); }</code>
我用的是mybatis,所以只需将mapper传进函数,如果不用mybatis,需要自己创建并关闭数据库连接。
延伸:数据库死锁
数据库死锁是事务性数据库 (如SQL Server, MySql等)经常遇到的问题。除非数据库死锁问题频繁出现导致用户无法操作,一般情况下数据库死锁问题不严重。在应用程序中进行try-catch就可以。那么数据死锁是如何产生的呢?
InnoDB实现的是行锁 (row level lock),分为共享锁 (S) 和 互斥锁 (X)。
共享锁用于事务read一行。
互斥锁用于事务update或delete一行。
当客户A持有共享锁S,并请求互斥锁X;同时客户B持有互斥锁X,并请求共享锁S。以上情况,会发生数据库死锁。如果还不够清楚,请看下面的例子。
数据库死锁例子
首先,客户A创建一个表T,并向T中插入一条数据,客户A开始一个select事务,所以拿着共享锁S。
<code class="language-sql">mysql> CREATE TABLE t (i INT) ENGINE = InnoDB; Query OK, 0 rows affected (1.07 sec) mysql> INSERT INTO t (i) VALUES(1); Query OK, 1 row affected (0.09 sec) mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE; +------+ | i | +------+ | 1 | +------+</code>
然后,客户B开始一个新事务,新事务是delete表T中的唯一一条数据。
<code class="language-sql">mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> DELETE FROM t WHERE i = 1;</code>
删除操作需要互斥锁 (X),但是互斥锁X和共享锁S是不能相容的。所以删除事务被放到锁请求队列中,客户B阻塞。
最后,客户A也想删除表T中的那条数据:
<code class="language-sql">mysql> DELETE FROM t WHERE i = 1; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction</code>
死锁产生了!因为客户A需要锁X来删除行,而客户B拿着锁X并正在等待客户A释放锁S。看看客户A,B的状态:
客户A: 拿着锁S,等待着客户B释放锁X。
客户B: 拿着锁X,等待着客户A释放锁S。
发生死锁后,InnoDB会为对一个客户产生错误信息并释放锁。返回给客户的信息:
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
所以,另一个客户可以正常执行任务。死锁结束。

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Prestasi pertanyaan MySQL boleh dioptimumkan dengan membina indeks yang mengurangkan masa carian daripada kerumitan linear kepada kerumitan logaritma. Gunakan PreparedStatements untuk menghalang suntikan SQL dan meningkatkan prestasi pertanyaan. Hadkan hasil pertanyaan dan kurangkan jumlah data yang diproses oleh pelayan. Optimumkan pertanyaan penyertaan, termasuk menggunakan jenis gabungan yang sesuai, membuat indeks dan mempertimbangkan untuk menggunakan subkueri. Menganalisis pertanyaan untuk mengenal pasti kesesakan; gunakan caching untuk mengurangkan beban pangkalan data;

Membuat sandaran dan memulihkan pangkalan data MySQL dalam PHP boleh dicapai dengan mengikuti langkah berikut: Sandarkan pangkalan data: Gunakan arahan mysqldump untuk membuang pangkalan data ke dalam fail SQL. Pulihkan pangkalan data: Gunakan arahan mysql untuk memulihkan pangkalan data daripada fail SQL.

Bagaimana untuk memasukkan data ke dalam jadual MySQL? Sambung ke pangkalan data: Gunakan mysqli untuk mewujudkan sambungan ke pangkalan data. Sediakan pertanyaan SQL: Tulis pernyataan INSERT untuk menentukan lajur dan nilai yang akan dimasukkan. Laksanakan pertanyaan: Gunakan kaedah query() untuk melaksanakan pertanyaan sisipan Jika berjaya, mesej pengesahan akan dikeluarkan.

Salah satu perubahan utama yang diperkenalkan dalam MySQL 8.4 (keluaran LTS terkini pada 2024) ialah pemalam "Kata Laluan Asli MySQL" tidak lagi didayakan secara lalai. Selanjutnya, MySQL 9.0 mengalih keluar pemalam ini sepenuhnya. Perubahan ini mempengaruhi PHP dan apl lain

Untuk menggunakan prosedur tersimpan MySQL dalam PHP: Gunakan PDO atau sambungan MySQLi untuk menyambung ke pangkalan data MySQL. Sediakan penyata untuk memanggil prosedur tersimpan. Laksanakan prosedur tersimpan. Proses set keputusan (jika prosedur tersimpan mengembalikan hasil). Tutup sambungan pangkalan data.

Mencipta jadual MySQL menggunakan PHP memerlukan langkah berikut: Sambung ke pangkalan data. Buat pangkalan data jika ia tidak wujud. Pilih pangkalan data. Buat jadual. Laksanakan pertanyaan. Tutup sambungan.

Pangkalan data Oracle dan MySQL adalah kedua-dua pangkalan data berdasarkan model hubungan, tetapi Oracle lebih unggul dari segi keserasian, skalabiliti, jenis data dan keselamatan manakala MySQL memfokuskan pada kelajuan dan fleksibiliti dan lebih sesuai untuk set data bersaiz kecil. ① Oracle menyediakan pelbagai jenis data, ② menyediakan ciri keselamatan lanjutan, ③ sesuai untuk aplikasi peringkat perusahaan ① MySQL menyokong jenis data NoSQL, ② mempunyai langkah keselamatan yang lebih sedikit, dan ③ sesuai untuk aplikasi bersaiz kecil hingga sederhana.

PHP menyediakan kaedah berikut untuk memadam data dalam jadual MySQL: DELETE statement: digunakan untuk memadamkan baris keadaan yang sepadan daripada jadual. Pernyataan TRUNCATETABLE: digunakan untuk mengosongkan semua data dalam jadual, termasuk ID yang dinaikkan secara automatik. Kes praktikal: Anda boleh memadamkan pengguna daripada pangkalan data menggunakan borang HTML dan kod PHP. Borang menyerahkan ID pengguna dan kod PHP menggunakan pernyataan DELETE untuk memadam rekod yang sepadan dengan ID daripada jadual pengguna.
