【发布时间】:2017-12-31 13:36:14
【问题描述】:
MySQL 如何允许将READ WRITE 事务设置为READ ONLY,但不能再次设置为READ WRITE?
以下@test 会导致SQLException assertThrow 显示并通过。
我已经阅读了https://dev.mysql.com/doc/refman/5.6/en/innodb-performance-ro-txn.html 的手册,其中陈述了相同的内容,但它似乎不真实。
将commit 移动到末尾可以避免Exception 抛出,但我很好奇为什么这是一个问题。尽管与此同时,我正在尝试考虑一个边缘情况,这将成为一个问题:)
@Test
void testSeparatedCommitBroken() throws SQLException {
try (DataConnection connection = ds.getConnection()) {
connection.setAutoCommit(false);
// first transaction
Map<String, Object> vals1 = new HashMap<>();
vals1.put("name", UUID.randomUUID().toString());
Long id1 = connection.insertRow("products", vals1);
assertNotNull(id1);
connection.commit(); // placing this at the end solves the problem
// check first transaction
Map<String, Object> row1 = connection.selectRow("products", new Pair<>("id", id1));
assertEquals(vals1.get("name"), row1.get("name"));
// second transaction
Map<String, Object> vals2 = new HashMap<>();
vals2.put("name", UUID.randomUUID().toString());
// the connection was set to read only by SELECT which can't be swapped back whilst in autocommit=false
assertThrows(SQLException.class, () -> {
connection.insertRow("products", vals2);
});
connection.setAutoCommit(true);
}
}
常规日志快照
2017-12-31T13:43:37.290875Z 7556 Connect root@localhost on using TCP/IP
2017-12-31T13:43:37.291062Z 7556 Query set autocommit=1
2017-12-31T13:43:37.296937Z 7556 Query SET CHARACTER SET utf8
2017-12-31T13:43:37.297194Z 7556 Query SET NAMES utf8
2017-12-31T13:43:37.298778Z 7556 Query USE `prod_info_mngr`
2017-12-31T13:43:37.298993Z 7556 Query set autocommit=1
2017-12-31T13:43:37.301601Z 7556 Query SET autocommit=0
2017-12-31T13:43:37.303049Z 7556 Query set session transaction read write
2017-12-31T13:43:37.305546Z 7556 Query select @@session.tx_read_only
2017-12-31T13:43:37.315099Z 7556 Query INSERT INTO products (name) VALUES (UUID())
2017-12-31T13:43:37.315814Z 7556 Query commit
2017-12-31T13:43:37.318989Z 7556 Query set session transaction read only
2017-12-31T13:43:37.319842Z 7556 Query select @@session.tx_read_only
2017-12-31T13:43:37.327934Z 7556 Query SELECT * FROM products WHERE id = 162 LIMIT 1
2017-12-31T13:43:37.336647Z 7556 Query set session transaction read write
2017-12-31T13:43:37.337431Z 7556 Query select @@session.tx_read_only
2017-12-31T13:43:37.346483Z 7556 Query INSERT INTO products (name) VALUES (UUID())
SQL 自己尝试一下(这种设计显然很愚蠢 - 如果您在每个 INSERT 上都提交,那么为什么还要关闭 AutoCommit):
CREATE DATABASE `prod_info_mngr` /*!40100 DEFAULT CHARACTER SET utf8 */;
use `prod_info_mngr`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
set autocommit=0;
set session transaction read write;
insert into products (`name`) values (UUID());
commit;
set session transaction read only;
select * from products;
set session transaction read write;
insert into products (`name`) values (UUID());
commit;
set autocommit=1;
select * from products;
【问题讨论】:
-
我不关注您问题的前半部分,但您在这里遇到异常并不奇怪。您正在提交事务,然后尝试在同一事务上再次插入。
-
@TimBiegeleisen 为了清楚起见,我将添加登录。而且你可以在同一个事务上多次提交。
-
我想我刚刚学到了一些新东西 :-)
-
@TimBiegeleisen 在过去的 15 年中每天都学到新东西!以这个问题为例。虽然通过更好的设计很容易避免。
-
我已经从您的日志中测试了 SQL,它适用于 MySQL 5.7.20
标签: mysql