0

要点に直行しましょう。新しい行をリレーショナル データベースに同時に挿入するアプリケーションがあります。1 つの多対 1 リレーションのエンドポイントで、後で使用するためにトリガーを使用して子行数を追跡したいと考えています。残念ながら、新しいデータに同じ親行 ( applicant) への参照が含まれている場合、DEADLOCKS が発生します。更新された行の同時ロックを取得するには? ここに私のトリガーがあります:

DROP TRIGGER IF EXISTS `incrementEntryCountTrigger`;

区切り記号 $$
CREATE TRIGGER `incrementEntryCountTrigger` AFTER INSERT ON trademark FOR EACH ROW
始める
    申請者の更新
        SET entryCount=entryCount+1,
            entryCountChanged=1
        WHERE 申請者.id=NEW.申請者_id;
END$$
区切り文字;



DROP TRIGGER IF EXISTS `decrementEntryCountTrigger`;
区切り記号 $$
CREATE TRIGGER `decrementEntryCountTrigger` AFTER DELETE ON商標の各行
    始める
        申請者の更新
            SET entryCount=entryCount-1,
                entryCountChanged=1
            WHERE 申請者.id=OLD.申請者_id;
    END$$
    区切り文字;

trademarkテーブルの構造

CREATE TABLE `trademark` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `applicationDate` 日時 DEFAULT NULL,
  `applicationNumber` varchar(255) DEFAULT NULL,
  `class` varchar(255) DEFAULT NULL,
  `creationDate` 日時 DEFAULT NULL,
  `deleted` tinyint(4) DEFAULT NULL,
  `imageDownloaded` tinyint(4) DEFAULT NULL,
  `modified` 日時 DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `registrationDate` datetime DEFAULT NULL,
  `登録番号` varchar(255) DEFAULT NULL,
  `trademarkType` varchar(255) DEFAULT NULL,
  `applicant_id` int(11) DEFAULT NULL,
  `country_id` int(11) DEFAULT NULL,
  `service_id` int(11) DEFAULT NULL,
  主キー (`id`)、
  UNIQUE KEY `uniqueApplicationPerServiceContraint` (`applicationNumber`,`service_id`),
  KEY `FK_sv7x27shne6cro3hch7who6vr` (`applicant_id`),
  KEY `FK_4fuuxl1srjn7svpby7rd6j1er` (`country_id`),
  KEY `FK_1g62lp3kjl15f789m7netvlsk` (`service_id`),
  CONSTRAINT `FK_1g62lp3kjl15f789m7netvlsk` FOREIGN KEY (`service_id`) REFERENCES `service` (`id`),
  CONSTRAINT `FK_4fuuxl1srjn7svpby7rd6j1er` FOREIGN KEY (`country_id`) REFERENCES `country` (`id`),
  制約 `FK_sv7x27shne6cro3hch7who6vr` 外部キー (`applicant_id`) 参照 `applicant` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2101 DEFAULT CHARSET=utf8
4

1 に答える 1

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

上記の外部キーは、デッドロックの原因です。

テーブルへの挿入ごとに、外部キー制約により、テーブルtrademark内の対応するレコードに共有ロックが設定されます。applicantこのロックは、データベースの整合性を確保するために、他のセッションが行を更新/削除するのを防ぐために DBMS によって配置されます。

次のシナリオを想像してください: 1. セッション 1 が、 applicant=2 のテーブルに
新しいレコードを挿入します。これにより、2 に共有ロックが設定されます。数ミリ秒後、セッション 2 が、applicant_id = 2 のテーブルに 別のレコードを挿入します。テーブル内の対応する行に対する共有ロック。共有ロックは競合しないため、現時点では何も起こりません。 3. セッション 1 でトリガーtrademarkapplicant.id = 2
trademarkapplicant
after insert起動されます - トリガーはテーブル内の行 id=2 を更新しようとしていapplicantます。セッション 2 によってロックされている (共有ロックが書き込みロックと競合する) ため、トランザクションは共有ロックの解放を待機しています。
4. セッション 2 でトリガーafter insertが起動されます。トリガーは同じ行を更新しようとしています。データベースは、セッション 2 がセッション 1 がロックしようとしているのと同じ行をロックしようとしていることを検出しますが、セッション 1 は実際にはセッション 2 によって配置されたロックを待機しています --> そのため、DBMS はデッドロック エラーを報告します (両方のセッションお互いに待っています)。

この問題に対処するためにできること:
1. 外部キー制約を削除しますが、これによりデータの整合性の問題が発生する可能性があります。2.次のコマンドを
追加します。before insert triggerbefore deleteSELECT 1 FROM applicant WHERE applicant.id = NEW.applicant_id FOR UPDATE-これにより、レコードに書き込みロックが設定され、デッドロックが防止されますが、すべての挿入操作が遅くなります。
3. アプリケーションでデッドロック エラーを検出し、INSERT 操作を再試行します。

于 2013-08-21T21:47:52.427 に答える