Deadlock when running SELECT x WHERE y FOR UPDATE

  Kiến thức lập trình

I’m using MySQL version 8.3.0 from a Docker image, with the default configuration.

I simplified my use-case to a table with just 2 columns. What I want to achieve is to block simultaneous transactions from inserting records for the same “group” (in this case to the same product_sku), but to allow them to insert for other “groups”.

By going through the docs at https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html I understood that by running SELECT x FROM y WHERE z FOR UPDATE I would only lock rows satisfying condition z, without locking all the other ones. However this doesn’t seem to be the case.

My table:

CREATE TABLE `example` (
  `id` int NOT NULL AUTO_INCREMENT,
  `product_sku` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `example_product_sku_IDX` (`product_sku`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

I run two MySQL sessions – AA and BB:

AA> BEGIN;
Query OK, 0 rows affected (0,00 sec)

AA> SHOW VARIABLES WHERE Variable_name='autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0,00 sec)

BB> BEGIN;
Query OK, 0 rows affected (0,00 sec)

BB> SHOW VARIABLES WHERE Variable_name='autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0,00 sec)

AA> SELECT COUNT(*) FROM example WHERE product_sku = 'abc' FOR UPDATE;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0,00 sec)

BB> SELECT COUNT(*) FROM example WHERE product_sku = 'def' FOR UPDATE;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0,00 sec)

AA> INSERT INTO example (product_sku) VALUES ('abc');
(this query hangs up...)

BB> INSERT INTO example (product_sku) VALUES ('def');
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

(at this point query from AA executes):
Query OK, 1 row affected (4,02 sec)

From my understanding the two locks should be independent, as they should lock different range of rows. However they are not.

I tried the below changes, without success:

  • removing the example_product_sku_IDX index
  • changing SELECT COUNT(*) to SELECT *

I’m trying to understand whether I’m doing something wrong or MySQL has a bug. I found a similar question on MySQL board, but it’s not very helpful in terms of explaining the problem – https://bugs.mysql.com/bug.php?id=96748

Theme wordpress giá rẻ Theme wordpress giá rẻ Thiết kế website

LEAVE A COMMENT