4

我打开了两个命令窗口来使用我的数据库(MySQL5)。

下面是我正在使用的表结构(应该注意,我已经通过执行关闭了自动提交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)

第 2 步 在第二个命令窗口中,我触发了下面的命令并且它挂起(似乎等待提交命令是来自上一个窗口的问题)

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

第 3 步 我转到命令窗口#1,然后执行commit;你可以看到下面的输出:

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

同时,我可以看到之前挂起的第二个窗口也执行了命令并打印在输出下方:

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

第 4 步 现在我在第二个窗口中发出 commit 以确保即使在第二个会话中也能正确提交所有更改:

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

第 5 步 现在,由于两个窗口都发出了提交,我认为一切都很好,两个会话也必须同步,所以我转到第一个命令窗口并发出以下命令:

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

我很惊讶,因为我City期望值是'Dublin'因为来自第二个命令窗口(即update)的更改已提交Step 4,但我仍在Wil列中City

我在这里做错了什么?

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- 需要权衡取舍。最值得注意的是,数据库在执行 a 时会获取范围锁,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 回答