• ベストアンサー
  • 困ってます

MySql5でのネクストロックについて

mysql5(repeatable read)のロック機構について勉強しています。 [sample1(主キー:id)] +----+---+ | id | point | +--+-----+ | 10 | 10 | | 15 | 15 | | 20 | 20 | | 25 | 25 | | 30 | 30 | +--+-----+ 上記のようなテーブルに対して、以下の2つのスレッド(A,B)にて SQLを発行した際、☆1部分は即時に実行されます。 (A) start transaction; (A) select * from sample1 where id >= 15 and id <= 25 for update;  (B) start transaction;  (B) insert into sample1 values(14, 14); #☆1  (B) rollback; (A) rollback; しかし、以下の2つのスレッド(A,B)にて SQLを発行した際、☆2部分は即時に実行されません。(スレッドAのロック解除待ちになります) (A) start transaction; (A) select * from sample1 where id >= 15 and id <= 25 for update;  (B) start transaction;  (B) insert into sample1 values(26, 26); #☆2 (A) rollback;  (B) rollback; ネクストロックという機構があることは存じているのですが、その具体的な仕組みがよくわかりません。 どうして、☆1が即時に実行され、☆2はロックがかかってしまうのでしょう?

共感・応援の気持ちを伝えよう!

  • MySQL
  • 回答数1
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • 回答No.1

こちらも参考に http://d.hatena.ne.jp/sh2/20090112 つまり、sample1の次のキーである「30 | 30 」までをロック範囲として認識するからです。 ですので、 INSERT INTO sample1 values ( 31, 31 ); は待ちになりません。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ご回答頂きまして、誠にありがとうございます。 教えて頂いたサイトを拝見させて頂きました。(以下、一部抜粋) ----------------------------------------------------- 特にc1 <= 30のときの挙動はなかなか強烈だと思います。 ----------------------------------------------------- まさしく、この部分でした。(強烈でした。) ※ネクストキーロックは、「次の(以降の)」ということなのですね。 この手のお話にお詳しそうなので、もう1つ質問させて頂きたいです。 (お時間があればで、結構です。) 例えば、今回の例にあるようなテーブル(sample1)に対して、 以下のような2つのスレッド(A,B)にてSQLを発行。 (A) start transaction; (A) select * from sample1 where id = 22 for update; #(1)  (B) start transaction;  (B) select * from sample1 where id = 23 for update; #(2) (A) insert into sample1 values(22, 22); ☆1  (B) insert into sample1 values(23, 23); ☆2 1. ☆1部分でロック獲得待ち。 2. ☆2でスレッドBがデッドロックにて終了(rollbackされる)。 3. ☆1実行される。 と、なります。 私は、 1. (1)にて、スレッドAが[20-25]間のギャップ排他ロックを獲得。 2. (2)にてスレッドBが[20-25]間のギャップ排他ロックを獲得。 と、(2)の時点でスレッドBにロックがかかると思っていましたが、かかりません。 ※explainしてみました。(where id = 23 としても、同様の結果となりました) explain select * from sample1 where id = 22 for update +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables | +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ ここからは、私の想像なのですが、 1. (1)にて、スレッドAが[20-25]間のギャップ共有ロックを獲得。 2. (2)にて、スレッドBが[20-25]間のギャップ共有ロックを獲得。 3. ☆1にて、[22]のインデックス排他ロックの獲得待ち。 4. ☆2にて、[23]のインデックス排他ロックの獲得待ち。 ⇒ デッドロック と、なっているのかなと...。 ⇒存在しないレコードへは、排他ロックではなく、共有ロックが獲得される。 ご回答を頂ければ幸いです。 ※ベストアンサーとさせて頂きました。

関連するQ&A

  • トランザクションについて

    トランザクションについての質問なのですが、下にある1のSQLを実行すると 'a'だけ登録されるのは、分かるのですが、 2のSQLを実行すると、'c'と'd'の両方が登録されてしまいます。 私的には、両方登録されないのかなぁと思っていたのですが・・・ COMMITが来た時点で、START TRANSACTIONの開始位置は、 あまり関係ないということなのでしょうか? よろしくお願いします。 1. START TRANSACTION; insert into test values('a'); START TRANSACTION; insert into mtuser values('b'); ROLLBACK; COMMIT; 2. START TRANSACTION; insert into test values('c'); START TRANSACTION; insert into mtuser values('d'); COMMIT; ROLLBACK; 環境:Mysql4.1.19

    • ベストアンサー
    • MySQL
  • トランザクションとテーブルロック

    初心者の質問で申し訳ありません。 トランザクションで複数のテーブルを更新する時、テーブルロックはかかっているのでしょうか。 具体的に言うと、 BEGIN TRAN a  INSERT INTO A VALUES('data1')  INSERT INTO B VALUES('data1','data2')  INSERT INTO C VALUES('data1','data2','data3') COMMIT TRAN a とするとき、テーブルA,B,Cはあらかじめロックしておく必要があるのでしょうか。 アドバイスお願いいたします。

  • mysqlのalter table中のロックについてです。

    mysqlのalter table中のロックについてです。 下記のように、alterでテーブルを再構築中に同じテーブルにinsertが実行された場合、 接続Bのinsertはブロックされるかと思うのですが、テーブルが大きくalterに時間がかかる場合、 タイムアウトなどは発生するのでしょうか。 またもし発生する場合、タイムアウト値の設定などの確認方法はあるのでしょうか。 1.接続A  alter table table1 add columnB int(11) ; 2.接続B(接続Aのalter実行中)  insert into table1(columnA) values('aaa');

    • ベストアンサー
    • MySQL
  • MySQLから取り出したものを3つに分ける

    MySQLに以下のようなSQLを打ちました。 create table table_list( id int, task varchar(255) ); insert into table_list values(1,'ほげほげ1-1'); insert into table_list values(1,'ほげほげ1-2'); insert into table_list values(2,'ほげほげ2-1); insert into table_list values(2,'ほげほげ2-2'); insert into table_list values(3,'ほげほげ3-1'); そして、空のdiv要素が3つあります。 このデータベースからidの数値別に、div要素へtaskの文字列を入れたいのですが、どうすればいいのでしょうか? SQLで「select * from table_list」をやってからtaskを取り出すのか、3回SQLで「select task from table_list where id=1」のようにするのがよろしいんでしょうか?

    • ベストアンサー
    • PHP
  • POSTGRESでMYSQLと同じ結果を得る方法

    create table test (a varchar(10), b varchar(10)); insert into test values ('a','a'); insert into test values ('b','b'); insert into test values ('b','c'); insert into test values ('c','d'); select count(*), a, b from test group by a; 上記を実行するとMYSQLでは +----------+------+------+ | count(*) | a | b | +----------+------+------+ | 1 | a | a | | 2 | b | b | | 1 | c | d | +----------+------+------+ という結果になる。 POSTGRESでは以下のエラーになります。 ERROR: column "test.b" must appear in the GROUP BY clause or be used in an aggr egate function select count(*), a, b from test group by a, b; とすると結果が変わってしまいます。 MYSQLと同じ結果をPOSTGRESで得るいい方法はありますか?

  • MySQLで漢字を登録したい。

    MySQLで漢字を登録したい。 insert into personal(id, old, name) values(1, 18, 'Satou'); とやればうまくいくのですが、 insert into personal(id, old, name) values(1, 18, '佐藤'); とやっても????となってしまいます。 どのようにすればいいでしょうか。

    • ベストアンサー
    • MySQL
  • MysqlでのLOCK処理

    Mysqlのwebリファレンスの http://dev.mysql.com/doc/refman/4.1/ja/lock-tables.htmlでは --->個々の UPDATE ステートメントでは、いずれも処理が原子的に行われるため、通常、テーブルをロックする必要はありません。現在実行中の SQL ステートメントが、他のスレッドによって妨害されることはまったくありません。しかし、次に示すように、テーブルをロックする必要が生じる場合もいくつかあります。 トランザクションをサポートしていないストレージエンジンを MySQL で使用している場合、SELECT と UPDATE の間に他のスレッドに割り込まれないようにするには、LOCK TABLES を使用する必要がある。次の例では、安全に処理を実行するために LOCK TABLES を発行する必要がある。<--- と説明がありますが、 (1)トランザクションをサポートしていないストレージエンジンでINSERT INTO,DELETE処理をするにはLOCKが必要になってくるのでしょうか? よろしくご教授おねがいします

  • MySQL初心者で困っています

    MySQL初心者です。 「やさしいJava活用編」を参考に,MySQLデータベース表を作成しました。 ソースは以下の通りです。 ---[Sample01.txt]----- CREATE DATEBASE sample01; use sample01; CREATE TABLE smpl_table (id int(10), name varchar(50)); INSERT INTO smpl_table VALUES (2, 'い'); INSERT INTO smpl_table VALUES (3, 'ろ'); INSERT INTO smpl_table VALUES (4, 'は'); SELECT * FROM smpl_table; ---ここまで----- 以下が実行コマンドです -------------- mysql> \. C:\Sample01.txt 以下が実行結果です。 -------------- ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DATEBASE sample01' at line 1 ERROR 1049 (42000): Unknown database 'sample01' ERROR 1046 (3D000): No database selected ERROR 1046 (3D000): No database selected ERROR 1046 (3D000): No database selected ERROR 1046 (3D000): No database selected ERROR 1046 (3D000): No database selected 以上のような結果が返ってきて正しく実行できません。 MySQLについて初心者なので 詳しいことがわからず困っています どなたかご教授お願いします。

  • ある条件の最大値+1を初番するにはロックが必要ですか?

    以下のテーブルでcolumn毎に連番を振る場合、 テーブルロックが必要でしょうか? テーブル test id column 1 a 2 a 1 b 新規データ登録手順 1.トランザクション 2.select max(id)+1 from test where column = b for update 3.insert test into (id,column) values (selectで取得した値,b) 4.トランザクション終了 これで、column毎に登録されているIDの最大値+1で 重複せずにデータのINSERTが保障されるでしょうか?

    • ベストアンサー
    • MySQL
  • MySQL初心者

    -mysql CREATE DATABASE testdb; use testdb; CREATE TABLE car_table(id int(10),name varchar(50)); INSERT INTO car_table VALUES (2,'乗用車'); INSERT INTO car_table VALUES (3,'オープンカー'); INSERT INTO car_table VALUES (4,'トラック'); SELECT * FROM car_table; これで間違ってるとは思わないんですが、なぜか ERROR 1049(42000): Unknown database 'testdb・・ とでます。なぜなんでしょうか?全然わかりません。 何かの設定ミスかなにかでしょうか?

    • ベストアンサー
    • MySQL