に行を挿入中に私たちは、並行処理モードでは、これらのロックmysqlの
1. Select active subscribers
SELECT *
FROM TEST_SUBSCRIBERS
WHERE SERVICE_ID='web-sub-1'
and MSISDN='000000002'
AND STATE IN ('ACTIVE', 'INACTIVE');
2. If there are no such subscribers, I can insert it
INSERT INTO TEST_SUBSCRIBERS
(SUBSCRIPTION_ID, MSISDN, STATE, SERVICE_ID)
VALUES ('web-sub-1-000000002-1504624819', '000000002', 'ACTIVE', 'web-sub-1');
のような(Javaで)アクションを実行する並列スレッドでテーブル
CREATE TABLE TEST_SUBSCRIBERS (
SUBSCRIPTION_ID varchar(255) NOT NULL COMMENT 'Subscriber id in format MSISDN-SERVICE_ID-TIMESTAMP',
MSISDN varchar(12) NOT NULL COMMENT 'Subscriber phone',
STATE enum ('ACTIVE', 'INACTIVE', 'UNSUBSCRIBED_SMS', 'UNSUBSCRIBED_PARTNER', 'UNSUBSCRIBED_ADMIN', 'UNSUBSCRIBED_REBILLING') NOT NULL,
SERVICE_ID varchar(255) NOT NULL COMMENT 'Id of service',
PRIMARY KEY (SUBSCRIPTION_ID)
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
を持っている2つのスレッドは、MSISDNに行を挿入しようとすることができます= "000000002"とservice-id = "web-sub-1"で、現在のタイムスタンプが異なる可能性があるため、異なるsubscriptionId。両方のスレッドが最初の選択を実行し、結果がゼロになり、両方のスレッドが挿入されます。そこで、これらの2つのクエリをトランザクションに結合しようとしますが、既存の行ではないロックの問題があります。挿入にロックが必要な場合などです。 この2つのアクションでは、すべてのテーブルをロックしたくないのです。この場合、システムの動作が遅すぎると思われるからです。 この状況のためにuniqキーを作成することはできません。なぜなら、1人の主体に対して、同じunsubscribed状態の複数の行が存在する可能性があるからです。同じサービスの2人の加入者を挿入しようとすると、プライマリキーには秒単位のタイムスタンプが含まれます。 私たちはSELECT ... FOR UPDATEとSELECT ... LOCK IN SHARE MODEを使用しようとしましたが、デッドロックが発生し、データベースサーバーの操作が重いです。私たちは2つのターミナルを開いて、ステップバイステップで行った試験では
:
# Window 1
mysql> start transaction;
mysql> SELECT SUBSCRIPTION_ID FROM TEST_SUBSCRIBERS s
WHERE s.SERVICE_ID="web-sub-1" AND s.MSISDN="000000002" FOR UPDATE;
# Window 2
start transaction;
mysql> SELECT SUBSCRIPTION_ID FROM TEST_SUBSCRIBERS s
WHERE s.SERVICE_ID="web-sub-1" AND s.MSISDN="000000002" FOR UPDATE;
# Window 1
mysql> INSERT INTO TEST_SUBSCRIBERS
(SUBSCRIPTION_ID, MSISDN, STATE, SERVICE_ID)
VALUES('web-sub-1-000000002-1504624818', '000000002', 'ACTIVE', 'web-sub-1');
# Window 2
mysql> INSERT INTO TEST_SUBSCRIBERS
(SUBSCRIPTION_ID, MSISDN, STATE, SERVICE_ID)
VALUES('web-sub-1-000000002-1504624819', '000000002', 'ACTIVE', 'web-sub-1');
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
はデッドロックせずに、完全なテーブルをロックすることなく、このような操作を行うための方法はありますか?我々が分析した他の変種は: 1.別表 2.不要な行の挿入と削除。
再生いただきありがとうございます。しかし、現在のタイムスタンプが異なる可能性があるため、同時実行モードの2つのスレッドでは、msisdn = "000000002"とservice-id = "web-sub-1"と異なるsubscriptionIdを持つ行を挿入しようとします。両方のスレッドが最初の選択を実行し、結果がゼロになり、両方のスレッドが挿入されます。だから、私たちがチェックできる2行については同じユニキーキーはありません。 –