4

データベース(MySQL5)を操作するために2つのコマンドウィンドウを開きました。

以下は、私が使用しているテーブル構造です(実行して自動コミットをオフにしたことに注意してくださいset autocommit=0;):

テーブル構造:

CREATE TABLE  `ajax`.`zipcodes` (
  `ZIPCODE` varchar(5) NOT NULL,
  `CITY` varchar(50) DEFAULT NULL,
  `STATE` varchar(2) DEFAULT NULL,
  PRIMARY KEY (`ZIPCODE`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

以下は一連の活動です。

ステップ1: コマンドウィンドウ1で、以下のコマンドを実行しました。出力も表示されます。

mysql> insert into ajax.zipcodes values(5, 'Wil', 'AK');
Query OK, 1 row affected (0.00 sec)

ステップ 22番目のコマンドウィンドウで、以下のコマンドを実行しましたが、ハングします(commitコマンドが前のウィンドウから発行されるのを待っているようです)

mysql> update ajax.zipcodes set city='Dublin' where zipcode=5;

ステップ3 コマンドウィンドウ#1に移動し、実行しましたcommit。以下の出力を見ることができます:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

同時に、以前にハングしていた2番目のウィンドウもコマンドを実行し、出力の下に出力されていることがわかりました。

mysql> update ajax.zipcodes set city='Dublin' where zipcode=5;
Query OK, 1 row affected (3.63 sec)
Rows matched: 1  Changed: 1  Warnings: 0

ステップ 42番目のウィンドウでcommitを発行して、2番目のセッションでもすべての変更が正しくコミットされるようにします。

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

ステップ5 コミットが両方のウィンドウから発行されたので、すべてが正常であり、2つのセッションも同期している必要があると思ったので、最初のコマンドウィンドウに移動し、以下のコマンドを発行します。

mysql> select * from zipcodes where zipcode=5;
+---------+------+-------+
| ZIPCODE | CITY | STATE |
+---------+------+-------+
| 5       | Wil  | AK    |
+---------+------+-------+
1 row in set (0.00 sec)

2番目のコマンドウィンドウ(つまり)からの変更がでコミットされたためにCity値を期待していたので驚きましたが、まだ列に入っています。'Dublin'updateStep 4WilCity

私はここで何が間違っているのですか?

4

1 に答える 1

4

これは、分離レベルと関係があります。SERIALIZABLE分離レベルを(MySQLのデフォルトは)に上げると、REPEATABLE READS「ファントム読み取り」は取得されません。

分離レベルとファントム読み取りについては、データベーストランザクション分離のWikipediaページで説明されています。

これをあなたと同じように実行すると、分離レベルが高くなり、期待どおりの結果が得られます。

セッション1

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE  `ajax`.`zipcodes` (
    ->   `ZIPCODE` varchar(5) NOT NULL,
    ->   `CITY` varchar(50) DEFAULT NULL,
    ->   `STATE` varchar(2) DEFAULT NULL,
    ->   PRIMARY KEY (`ZIPCODE`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.07 sec)

mysql> insert into ajax.zipcodes values(5, 'Wil', 'AK');
Query OK, 1 row affected (0.00 sec)

セッション2

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Query OK, 0 rows affected (0.00 sec)

mysql> update ajax.zipcodes set city='Dublin' where zipcode=5;

セッション1

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

セッション2

/* continued from previous (was frozen) */
Query OK, 1 row affected (7.54 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)

セッション1

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)

注意:これは、必ずしも常に使用する必要があることを意味するわけではありませんSERIALIZABLE。トレードオフがあります。最も注目すべきは、データベースがを実行するときに範囲ロックを取得し、ロックSELECTベースの競合が増えることです。

更新-トランザクションを明示的に処理する

これらのスクリプトを設定したのでautocommit=0;、実際には、トランザクションを期待するのではなく、明示的に処理する必要があります。START TRANSACTIONただし、ほとんどの場合、データベースは、実行した場合に期待どおりに動作しますSTART TRANSACTION

ただし、すべてのトランザクション(単なるトランザクションを含む)を明示的に開始および終了しながら元の例を実行するSELECTと、異なる結果が得られます。

セッション1

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE  `ajax`.`zipcodes` (
    ->   `ZIPCODE` varchar(5) NOT NULL,
    ->   `CITY` varchar(50) DEFAULT NULL,
    ->   `STATE` varchar(2) DEFAULT NULL,
    ->   PRIMARY KEY (`ZIPCODE`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.07 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into ajax.zipcodes values(5, 'Wil', 'AK');
Query OK, 1 row affected (0.00 sec)

セッション2

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> update ajax.zipcodes set city='Dublin' where zipcode=5;

セッション1

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

セッション2

/* continued from previous (was frozen) */
Query OK, 1 row affected (8.32 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

セッション1

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY   | STATE |
+---------+--------+-------+
| 5       | Dublin | AK    |
+---------+--------+-------+
1 row in set (0.00 sec)
于 2011-04-20T14:59:26.363 に答える