mysql - 使用 LOCK TABLES 回滚事务

标签 mysql transactions locking innodb

我有一个 PHP/5.2 驱动的应用程序,它使用 MySQL/5.1 下的事务,因此如果遇到错误条件,它可以回滚多个插入。我有不同的可重用函数来插入不同类型的项目。到目前为止一切顺利。

现在我需要对某些插入使用表锁定。正如官方手册所建议的那样,我使用 SET autocommit=0 而不是 START TRANSACTION 所以 LOCK TABLES 不会发出隐式提交。而且,如文档所述,解锁表会隐式提交任何事件事务:

问题就在这里:如果我简单地避免 UNLOCK TABLES,第二次调用 LOCK TABLES 会提交挂起的更改!

看起来唯一的方法是在单个语句中执行所有必要的LOCK TABLES。这是维护的噩梦。

此问题是否有合理的解决方法?

这是一个小测试脚本:

DROP TABLE IF EXISTS test;

CREATE TABLE test (
    test_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    random_number INT(10) UNSIGNED NOT NULL,
    PRIMARY KEY (test_id)
)
COLLATE='utf8_spanish_ci'
ENGINE=InnoDB;


-- No table locking: everything's fine
START TRANSACTION;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;



-- Table locking: everything's fine if I avoid START TRANSACTION
SET autocommit=0;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;



-- Table locking: I cannot nest LOCK/UNLOCK blocks
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
UNLOCK TABLES; -- Implicit commit
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;


-- Table locking: I cannot chain LOCK calls ether
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
LOCK TABLES test WRITE; -- Implicit commit
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;

最佳答案

显然,LOCK TABLES 无法固定以与事务配合使用。解决方法是将其替换为 SELECT .... FOR UPDATE .您不需要任何特殊语法(您可以使用常规的 START TRANSACTION)并且它按预期工作:

START TRANSACTION;
SELECT COUNT(*) FROM foo FOR UPDATE; -- Lock issued
INSERT INTO foo (foo_name) VALUES ('John');
SELECT COUNT(*) FROM bar FOR UPDATE; -- Lock issued, no side effects
ROLLBACK; -- Rollback works as expected

请注意,COUNT(*) 只是一个示例,您通常可以使用 SELECT 语句来获取您实际需要的数据;-)

(此信息由 Frank Heikens 提供。)

关于mysql - 使用 LOCK TABLES 回滚事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4849318/

相关文章:

php - 如何检测 MySQL 中的隐式提交?

PHP stripslashes,拦截MySQL SELECT

mysql - 带条件的 SQL 连接表查找

sql - SQL Server 中的嵌套 SQL 事务

concurrency - (websocket) Golang 同步数据锁定失败 - Broken Pipe

database - "select for update"什么时候加锁和解锁?

Android:Slidingdrawer.lock() 阻止其余布局的触摸输入

php - ON DUPLICATE KEY UPDATE 值为 0

MySQL 不唯一的表/别名

java - org.springframework.transaction.CannotCreateTransactionException : Could not open Hibernate Session for transaction