次のスキーマを検討してください:(便宜上、Rem stmtsを残しておきます) :
-- drop table if exists spies;
create table spies
( id int primary key,
weapon_id int not null,
name varchar(100) not null,
key(weapon_id),
foreign key (weapon_id) references weapons(id)
)engine=InnoDB;
-- drop table if exists weapons;
create table weapons
( id int primary key,
name varchar(100) not null
)engine=InnoDB;
insert weapons(id,name) values (1,'slingshot'),(2,'Ruger');
insert spies(id,weapon_id,name) values (1,2,'Sally');
-- truncate table spies;
これで、P1とP2の2つのプロセスができました。 P1がおそらくMySQLWorkbenchであり、P2がMySqlコマンドラインウィンドウである場合をテストするのに最適です。つまり、これを個別の接続として設定する必要があります。これらを適切な方法で段階的に実行するためには、細心の注意を払う必要があります(説明で説明されています)。 以下)、他のプロセスウィンドウへの影響を確認してください。
明示的なトランザクションにラップされていないmysqlクエリは、それ自体が暗黙的なトランザクションであることに注意して、次のクエリを検討してください。しかし、以下では、私は明示的に振った:
Q1:
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1;
-- place2
COMMIT;
Q2:
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond' WHERE id = 1;
-- place2
COMMIT;
Q3:
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from weapons where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
Q4:
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from spies where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
Q5(クエリの寄せ集め):
SELECT * from weapons;
SELECT * from spies;
物語
Q1: P1が開始したときQ1 、そしてplace2に到達すると、id =1行(合計2行、各テーブルに1行)のテーブル武器とスパイの両方で排他的な行レベルの更新ロックを取得しました。これは、P2がQ3の実行を開始し、place1に到達しますが、place2でブロックし、P1がCOMMITの呼び出しに到達したときにのみ解放されることで証明できます。 Q3を実行しているP2について私が今言ったことはすべて、Q4を実行しているP2についても同じです。要約すると、P2画面では、place2はP1コミットまでフリーズします。
暗黙のトランザクションについての注意。 あなたの本当の Q1クエリはこれを非常に高速に実行し、そこから出てくると暗黙のコミットが実行されます。ただし、前の段落では、時間のかかるルーチンを実行する必要があったため、詳細を説明しています。
Q2: P1が開始したときQ2 、そしてplace2に到達すると、id =1行(合計2行、各テーブルに1行)のテーブル武器とスパイの両方で排他的な行レベルの更新ロックを取得しました。ただし、P2にはQ3のweapons
のブロックに関する問題はありません。 、ただし、P2にはplace2 spies
でQ4を実行する際のブロックの問題があります 。
したがって、Q1とQ2の違いは、FKインデックスがUPDATEの列に関連していないことを知っているMySQLにあり、マニュアルには注1 以下。
P1がQ1を実行する場合、P2はQ5タイプのクエリを取得する読み取り専用の非ロックに問題はありません。唯一の問題は、設定されている分離レベルに基づいてP2が認識するデータレンディションです。
注1 :異なるによって設定されたロックInnoDBのSQLステートメント :
上記の理由により、 Q2: これは、P2が自由にUPDATEを実行したり、weapons
に対してUPDATE専用のモーメンタリロックを取得したりできるようなものです。 。これは、エンジンがweapon_idでP1を使用してUPDATEを実行していないため、そのテーブルに行レベルのロックがないためです。
これを50,000フィートに戻すための最大の懸念事項は、暗黙のトランザクション(START / COMMITのないトランザクション)またはCOMMITの前の明示的なトランザクションのいずれかでロックが保持される期間です。理論上、ピアプロセスがUPDATEの必要性を無期限に取得することを禁止できます。ただし、そのロックを取得しようとするたびに、 innodb_lock_wait_timeout 。つまり、デフォルトでは、約60秒後にタイムアウトになります。設定を表示するには、次を実行します:
select @@innodb_lock_wait_timeout;
私の場合、現時点では50(秒)です。