MySQL8.0の行ロックの仕様について


MySQL8.0にて、`SELECT...FOR UPDATE
NOWAIT`で行ロックを取得しようとした際、SELECTが空振りした際にもギャップロックがかかる認識で、`performance_schema.data_locks`にもレコードが追加されていることを確認したのですが、エラーになることを期待して別セッションで同じ条件の`SELECT...FOR
UPDATE
NOWAIT`を実行した際にエラーにならずロックがとれてしまいました(`performance_schema.data_locks`にレコードが増えた)。

この時、後続のセッションで期待通りのエラーを起こすための手段があればご教示いただきたきたいです。

質問の背景  
DBにアクセスしてデータをINSERTするアプリを作成しており、AUTO_INCREMENTが使えない状況下で並列でINSERTされることを想定して、事前に`SELECT...FOR
UPDATE NOWAIT`で行ロックをかけて、ロックされていればアプリ側でエラーハンドリングするような設計をしていました。




# 回答ではありません。

(なので最も役に立つ回答などではないのでご注意を)  
コメントに書いたDEADLOCKの件の現象確認用スクリプトです。

[code]

    cat >docker-compose.yml <<EOF
    version: '3.1'
    services:
      db:
        image: mysql
        command: --default-authentication-plugin=mysql_native_password
        volumes:
          - ./data:/var/lib/mysql
          - ./logs:/var/log/mysql
        ports:
          - 3306:3306
        environment:
          MYSQL_ROOT_PASSWORD: example
    EOF
    docker compose up -d
    docker compose exec -T db bash <<EOF
    while ! mysql --password=example </dev/null 2>/dev/null; do
        sleep 1
    done
    mysql --verbose --password=example <<EOF2
    -- drop database hoge;
    create database hoge;
    use hoge;
    create table hoge(
    id varchar(100) primary key,
    value numeric
    );
    EOF2
    EOF
    docker compose exec -T db bash <<EOF &
    mysql --verbose --table --database=hoge --password=example <<EOF2
    select version();
    begin;
    set profiling=1;
    select * from hoge where id='1' for update nowait;
    select sleep(3);
    insert into hoge values('1', 1);
    commit;
    show profiles;
    EOF2
    EOF
    docker compose exec -T db bash <<EOF &
    mysql --verbose --table --database=hoge --password=example <<EOF2
    select version();
    begin;
    set profiling=1;
    select * from hoge where id='1' for update nowait;
    select sleep(3);
    insert into hoge values('1', -1);
    commit;
    show profiles;
    EOF2
    EOF
    wait
    docker compose down
    
[/code]

実行結果

[code]

    [+] Running 2/2
     ✔ Network tmp_default  Created                                                                                                                                                         0.1s 
     ✔ Container tmp-db-1   Started                                                                                                                                                         1.4s 
    mysql: [Warning] Using a password on the command line interface can be insecure.
    --------------
    -- drop database hoge;
    --------------
    
    --------------
    create database hoge
    --------------
    
    --------------
    create table hoge(
    id varchar(100) primary key,
    value numeric
    )
    --------------
    
    mysql: [Warning] Using a password on the command line interface can be insecure.
    mysql: [Warning] Using a password on the command line interface can be insecure.
    --------------
    select version()
    --------------
    
    +-----------+
    | version() |
    +-----------+
    | 8.2.0     |
    +-----------+
    --------------
    begin
    --------------
    
    --------------
    set profiling=1
    --------------
    
    --------------
    select * from hoge where id='1' for update nowait
    --------------
    
    --------------
    select sleep(3)
    --------------
    
    +----------+
    | sleep(3) |
    +----------+
    |        0 |
    +----------+
    --------------
    insert into hoge values('1', 1)
    --------------
    
    ERROR 1213 (40001) at line 6: Deadlock found when trying to get lock; try restarting transaction
    --------------
    select version()
    --------------
    
    +-----------+
    | version() |
    +-----------+
    | 8.2.0     |
    +-----------+
    --------------
    begin
    --------------
    
    --------------
    set profiling=1
    --------------
    
    --------------
    select * from hoge where id='1' for update nowait
    --------------
    
    --------------
    select sleep(3)
    --------------
    
    +----------+
    | sleep(3) |
    +----------+
    |        0 |
    +----------+
    --------------
    insert into hoge values('1', -1)
    --------------
    
    --------------
    commit
    --------------
    
    --------------
    show profiles
    --------------
    
    +----------+------------+---------------------------------------------------+
    | Query_ID | Duration   | Query                                             |
    +----------+------------+---------------------------------------------------+
    |        1 | 0.01331375 | select * from hoge where id='1' for update nowait |
    |        2 | 3.00098250 | select sleep(3)                                   |
    |        3 | 0.04366000 | insert into hoge values('1', -1)                  |
    |        4 | 0.00948575 | commit                                            |
    +----------+------------+---------------------------------------------------+
    [+] Running 2/2
     ✔ Container tmp-db-1   Removed                                                                                                                                                         2.3s 
     ✔ Network tmp_default  Removed
    
[/code]

* * *

どういう理由でわざわざマイナス評価をしたのか知りませんが、別に手段があれば修正しますので、意図を明確にしてください。

回答ではないと書いてるのに回答でないからマイナス評価だとすると、他に手段がないので仕方ないです。コメント欄にコードなどを記載出来ればいいのですけどStackoverflowではそれが出来ないので。何か私が勘違いしてることなどあれば教えて頂けないと気付けません。言い争いをして意味不明な通報から削除されると却って意味が分からなくなりますが、私はきちんと意味のある話しかしないので、堂々と主張してください。




# 回答ではありません。

(なので最も役に立つ回答などではないのでご注意を)  
コメントに書いたDEADLOCKの件の現象確認用スクリプトです。

[code]

    cat >docker-compose.yml <<EOF
    version: '3.1'
    services:
      db:
        image: mysql
        command: --default-authentication-plugin=mysql_native_password
        volumes:
          - ./data:/var/lib/mysql
          - ./logs:/var/log/mysql
        ports:
          - 3306:3306
        environment:
          MYSQL_ROOT_PASSWORD: example
    EOF
    docker compose up -d
    docker compose exec -T db bash <<EOF
    while ! mysql --password=example </dev/null 2>/dev/null; do
        sleep 1
    done
    mysql --verbose --password=example <<EOF2
    -- drop database hoge;
    create database hoge;
    use hoge;
    create table hoge(
    id varchar(100) primary key,
    value numeric
    );
    EOF2
    EOF
    docker compose exec -T db bash <<EOF &
    mysql --verbose --table --database=hoge --password=example <<EOF2
    select version();
    begin;
    set profiling=1;
    select * from hoge where id='1' for update nowait;
    select sleep(3);
    insert into hoge values('1', 1);
    commit;
    show profiles;
    EOF2
    EOF
    docker compose exec -T db bash <<EOF &
    mysql --verbose --table --database=hoge --password=example <<EOF2
    select version();
    begin;
    set profiling=1;
    select * from hoge where id='1' for update nowait;
    select sleep(3);
    insert into hoge values('1', -1);
    commit;
    show profiles;
    EOF2
    EOF
    wait
    docker compose down
    
[/code]

実行結果

[code]

    [+] Running 2/2
     ✔ Network tmp_default  Created                                                                                                                                                         0.1s 
     ✔ Container tmp-db-1   Started                                                                                                                                                         1.4s 
    mysql: [Warning] Using a password on the command line interface can be insecure.
    --------------
    -- drop database hoge;
    --------------
    
    --------------
    create database hoge
    --------------
    
    --------------
    create table hoge(
    id varchar(100) primary key,
    value numeric
    )
    --------------
    
    mysql: [Warning] Using a password on the command line interface can be insecure.
    mysql: [Warning] Using a password on the command line interface can be insecure.
    --------------
    select version()
    --------------
    
    +-----------+
    | version() |
    +-----------+
    | 8.2.0     |
    +-----------+
    --------------
    begin
    --------------
    
    --------------
    set profiling=1
    --------------
    
    --------------
    select * from hoge where id='1' for update nowait
    --------------
    
    --------------
    select sleep(3)
    --------------
    
    +----------+
    | sleep(3) |
    +----------+
    |        0 |
    +----------+
    --------------
    insert into hoge values('1', 1)
    --------------
    
    ERROR 1213 (40001) at line 6: Deadlock found when trying to get lock; try restarting transaction
    --------------
    select version()
    --------------
    
    +-----------+
    | version() |
    +-----------+
    | 8.2.0     |
    +-----------+
    --------------
    begin
    --------------
    
    --------------
    set profiling=1
    --------------
    
    --------------
    select * from hoge where id='1' for update nowait
    --------------
    
    --------------
    select sleep(3)
    --------------
    
    +----------+
    | sleep(3) |
    +----------+
    |        0 |
    +----------+
    --------------
    insert into hoge values('1', -1)
    --------------
    
    --------------
    commit
    --------------
    
    --------------
    show profiles
    --------------
    
    +----------+------------+---------------------------------------------------+
    | Query_ID | Duration   | Query                                             |
    +----------+------------+---------------------------------------------------+
    |        1 | 0.01331375 | select * from hoge where id='1' for update nowait |
    |        2 | 3.00098250 | select sleep(3)                                   |
    |        3 | 0.04366000 | insert into hoge values('1', -1)                  |
    |        4 | 0.00948575 | commit                                            |
    +----------+------------+---------------------------------------------------+
    [+] Running 2/2
     ✔ Container tmp-db-1   Removed                                                                                                                                                         2.3s 
     ✔ Network tmp_default  Removed
    
[/code]

* * *

どういう理由でわざわざマイナス評価をしたのか知りませんが、別に手段があれば修正しますので、意図を明確にしてください。

回答ではないと書いてるのに回答でないからマイナス評価だとすると、他に手段がないので仕方ないです。コメント欄にコードなどを記載出来ればいいのですけどStackoverflowではそれが出来ないので。何か私が勘違いしてることなどあれば教えて頂けないと気付けません。言い争いをして意味不明な通報から削除されると却って意味が分からなくなりますが、私はきちんと意味のある話しかしないので、堂々と主張してください。

