0

让我们直奔主题。我有同时将新行插入关系数据库的应用程序。在一个多对一关系的端点上,我想使用触发器跟踪子行计数以供以后使用。applicant不幸的是,如果新数据包含对同一父行( )的引用,我会遇到死锁。如何获取更新行的并发锁?这是我的触发器:

如果存在 `incrementEntryCountTrigger` 则删除触发器;

分隔符 $$
在每行插入商标后创建触发器`incrementEntryCountTrigger`
开始
    更新申请人
        SET entryCount=entryCount+1,
            entryCountChanged=1
        WHERE申请人.id=NEW.applicant_id;
结束$$
分隔符;



如果存在 `decrementEntryCountTrigger` 则删除触发器;
分隔符 $$
删除每一行的商标后创建触发器`decrementEntryCountTrigger`
    开始
        更新申请人
            SET entryCount=entryCount-1,
                entryCountChanged=1
            WHERE申请人.id=OLD.applicant_id;
    结束$$
    分隔符;

trademark表结构

创建表`商标`(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `applicationDate` 日期时间 DEFAULT NULL,
  `applicationNumber` varchar(255) 默认为空,
  `class` varchar(255) 默认为空,
  `creationDate` 日期时间 DEFAULT NULL,
  `deleted` tinyint(4) 默认为空,
  `imageDownloaded` tinyint(4) 默认为空,
  `modified` datetime 默认为 NULL,
  `name` varchar(255) 默认为空,
  `registrationDate` 日期时间 DEFAULT NULL,
  `registrationNumber` varchar(255) 默认为空,
  `trademarkType` varchar(255) 默认为空,
  `applicant_id` int(11) 默认为空,
  `country_id` int(11) 默认为空,
  `service_id` int(11) 默认为 NULL,
  主键(`id`),
  唯一键`uniqueApplicationPerServiceContraint`(`applicationNumber`,`service_id`),
  KEY `FK_sv7x27shne6cro3hch7who6vr`(`applicant_id`),
  KEY `FK_4fuuxl1srjn7svpby7rd6j1er`(`country_id`),
  KEY `FK_1g62lp3kjl15f789m7netvlsk` (`service_id`),
  约束 `FK_1g62lp3kjl15f789m7netvlsk` 外键 (`service_id`) 参考 `service` (`id`),
  约束`FK_4fuuxl1srjn7svpby7rd6j1er`外键(`country_id`)参考`country`(`id`),
  约束 `FK_sv7x27shne6cro3hch7who6vr` 外键 (`applicant_id`) 参考 `applicant` (`id`)
) 引擎=InnoDB AUTO_INCREMENT=2101 默认字符集=utf8
4

1 回答 1

3
CREATE TABLE `trademark` (    
.......
CONSTRAINT `FK_sv7x27shne6cro3hch7who6vr` FOREIGN KEY (`applicant_id`) 
    REFERENCES `applicant` (`id`)
.....

上述外键是死锁的来源。由于外键约束,

每次插入trademark表中都会在表中的相应记录上放置一个共享锁。applicant此锁由 DBMS 放置,以防止其他会话更新/删除行以确保数据库完整性。

想象以下场景:
1. 会话 1 将一条新记录插入到trademark申请者 = 2 的表中 - 这在 2 上放置了一个共享锁applicant.id = 2
。几毫秒后,会话 2 将另一条记录插入到trademark申请者 ID = 2 的表中 - 这也放置了一个applicant表中对应行的共享锁。共享锁不冲突,所以此时什么都没有发生。
3.在会话1中触发after insert被触发 - 触发器正在尝试更新applicant表中的行 id=2。由于它被会话 2 锁定(共享锁与写锁冲突) - 因此事务正在等待释放共享锁。
4. 在会话 2 中,触发器after insert被触发 - 触发器试图更新同一行。数据库检测到,会话 2 正在尝试锁定会话 1 尝试锁定的同一行,但会话 1 实际上正在等待会话 2 放置的锁 --> 因此 DBMS 报告死锁错误(两个会话互相等待)。

您可以做些什么来解决这个问题:
1. 删除外键约束——但这会导致数据完整性问题。
2.用一个命令添加一个before insert trigger(也可能是):before deleteSELECT 1 FROM applicant WHERE applicant.id = NEW.applicant_id FOR UPDATE- 这将在记录上设置写锁并防止死锁,但会减慢所有插入操作。
3. 检测应用程序中的死锁错误并重试 INSERT 操作。

于 2013-08-21T21:47:52.427 回答