插入行期间,我们有表锁定在MySQL
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;
在我们执行操作(在Java)这样的
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');
在并发模式并行线程2个线程可以尝试与MSISDN插入行=“000000002”和service-id =“web-sub-1”和不同的subscriptionId,因为当前时间戳可能不同。两个线程都执行第一次选择,获得零结果并插入。所以我们试图将这两个查询加入到tranaction中,但是对于不存在的行锁定存在问题 - 当我们需要锁定插入或类似的东西时。 而我们不想在这2个动作中锁定所有的表格,因为我们假设我们的系统在这种情况下工作速度太慢。 我们不能为这种情况创建uniq键,因为对于一个abonent可以有多个具有相同unsubscribed状态的行。如果我们尝试为同一服务插入2个订户,则主键可以包含具有不同秒数的时间戳。 我们尝试使用SELECT ... FOR UPDATE和SELECT ... LOCK进入共享模式,但是我们遇到了死锁问题,并且它对数据库服务器来说操作很繁琐。
为了测试我们打开了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行没有uniq键。 –