6 mysql
编辑:我在这里找到了一个解决方案http://mysql.bigresource.com/Track/mysql-8TvKWIvE/ 假设select需要很长时间才能执行,这会锁定表很长一段时间吗?
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT foo FROM bar WHERE wee = 'yahoo!'; DELETE FROM bar WHERE wee = 'yahoo!'; COMMIT;
我希望使用一个条件来选择mysql中的行,将它们作为结果集返回到我的应用程序,然后删除这些行.如何才能做到这一点?我知道我可以做以下但是效率太低:
select * from MyTable t where _critera_. //get the resultset and then delete from MyTable t where t.id in(...result...)
我需要使用交易吗?有一个查询解决方案吗?
我需要SELECT根据某些条件对某些行进行处理,对数据进行处理,然后DELETE以原子方式处理这些相同的行,也就是说,不删除任何符合条件但插入到SELECT.
相反,其他的答案,REPEATABLE READ是不足够的。请参阅一致的非锁定读取。特别注意这个标注:
数据库状态的快照适用
SELECT于事务中的语句,不一定适用于 DML 语句。如果您插入或修改某些行然后提交该事务,则从另一个并发事务发出的DELETEorUPDATE语句REPEATABLE READ可能会影响那些刚刚提交的行,即使会话无法查询它们。
你可以自己试试:
首先创建一个表:
CREATE TABLE x (i INT NOT NULL, PRIMARY KEY (i)) ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)
启动事务并检查表(现在称为会话 1):
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM x;
Run Code Online (Sandbox Code Playgroud)
启动另一个会话(会话 2)并插入一行。请注意,此会话处于自动提交模式。
INSERT INTO x VALUES (1);
SELECT * FROM x;
Run Code Online (Sandbox Code Playgroud)
您将看到新插入的行。然后再次回到会话 1:
SELECT * FROM x;
DELETE FROM x;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
在会话 2 中:
SELECT * FROM x;
Run Code Online (Sandbox Code Playgroud)
您会看到,即使您从SELECT会话 1 中什么也没得到,您还是删除了一行。在会话 2 中,您将看到最后的表是空的。请特别注意会话 1 的以下输出:
mysql> SET 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> SELECT * FROM x;
Empty set (0.00 sec)
/* --- insert in session 2 happened here --- */
mysql> SELECT * FROM x;
Empty set (0.00 sec)
mysql> DELETE FROM x;
Query OK, 1 row affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT * FROM x;
Empty set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
此测试是使用 MySQL 5.5.12 完成的。
SERIALIZABLE事务隔离级别。但是请注意,会话 2 将在INSERT.SELECT...FOR UPDATE也能解决问题。我还没有 100% 深入研究手册来理解这一点,但是当我尝试它时它起作用了。优点是您不必更改事务隔离级别。同样,会话 2 将在INSERT.SELECT。基本上,您必须在 中包含一个唯一的列(主键会很好)SELECT,然后使用DELETE FROM x WHERE i IN (...)或类似的东西,其中IN包含SELECT的结果集中的键列表。优点是您根本不需要使用事务,并且会话 2 不会在任何时候被阻塞。缺点是您有更多的数据要来回发送到 SQL 服务器。此外,我不知道,如果删除行分别是同样有效使用相同的WHERE条款与原SELECT,但如果原来SELECT的WHERE条款很复杂或减缓个别删除可能会更快,所以这可能是另一个优势。为了社论,这是非常危险的事情之一,即使它被记录下来,它也几乎可以被认为是一个“错误”。但是,嘿,MySQL 设计者没有问我(或其他任何人,显然)。
我需要使用事务吗?有单一的查询解决方案吗?
是的,您需要使用事务。您不能在单个查询中删除和选择行(即,无法“返回”或“选择”已删除的行)。
您不一定需要执行该REPEATABLE READ选项 - 我相信您也可以选择行FOR UPDATE,尽管这是更高级别的锁定。REPEATABLE READ似乎是您可以用来安全地执行此事务的最低级别的锁定。它恰好是 InnoDB 的默认设置。
这对您的表有多大影响取决于您是否在该wee列上有索引。没有它,我相信 MySQL 将不得不锁定写入整个表。
进一步阅读: