我打开了两个命令窗口来处理我的数据库(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
。
我在这里做错了什么?
答案 0 :(得分:4)
这与隔离级别有关。如果将隔离级别提高到SERIALIZABLE
(MySQL中的默认值为REPEATABLE READS
),则不会出现“幻像读取”。
Wikipedia page for database transaction isolation上描述了隔离级别和幻像读取。
如果我按照你的方式运行,但是隔离级别越高,我就会得到你期望的结果。
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)
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;
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
/* 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)
mysql> select * from zipcodes;
+---------+--------+-------+
| ZIPCODE | CITY | STATE |
+---------+--------+-------+
| 5 | Dublin | AK |
+---------+--------+-------+
1 row in set (0.00 sec)
NB:这并不一定意味着您应该始终使用SERIALIZABLE
- 这需要权衡利弊。最值得注意的是,数据库在执行SELECT
时将获得范围锁定,并且您将获得更多基于锁定的冲突。
由于我们在这些脚本中设置了autocommit=0;
,我们确实应该明确地处理事务,而不是期望START TRANSACTION
- 尽管在大多数情况下,数据库的行为与您期望的一样{ d执行START TRANSACTION
。
但是,在明确开始和结束所有交易(包括仅SELECT
的交易时)运行原始示例,您会得到不同的结果:
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)
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;
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
/* 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)
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)