mysql选择删除
编辑: 我在这里找到了解决办法 假设select需要很长时间才能执行,那么它会很长时间锁定表吗 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT foo FROM bar WHERE wee = 'yahoo!'; DELETE FROM bar WHERE wee = 'yahoo!'; COMMIT; 设置会话事务隔离级别可重复读取; 启动交易; 从wee='yahoo!'所在的栏中选择foo; 从wee='yahoo!'所在的栏中删除; 犯罪 我希望使用一个条件来选择mysql中的行,将它们作为resultset返回到我的应用程序,然后删除这些行。如何做到这一点?我知道我可以做到以下几点,但效率太低了: select * from MyTable t where _critera_. //get the resultset and then delete from MyTable t where t.id in(...result...) 从MyTable t中选择*,其中_critera。 //获取结果集,然后 从MyTable t中删除,其中t.id位于(…结果…)mysql选择删除,mysql,Mysql,编辑: 我在这里找到了解决办法 假设select需要很长时间才能执行,那么它会很长时间锁定表吗 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT foo FROM bar WHERE wee = 'yahoo!'; DELETE FROM bar WHERE wee = 'yahoo!'; COMMIT; 设置会话事务隔离级别可重复读取; 启动交易; 从wee='yahoo!'所在
我需要使用事务处理吗?有单一的查询解决方案吗?没有单一的查询解决方案。使用
select * from MyTable t where _critera_
//get the resultset and then
delete from MyTable where _critera_
使用WHERE子句执行SELECT语句,然后在DELETE语句中使用相同的WHERE子句。假设数据没有临时更改,则应删除相同的行 编辑:是的,您可以将其设置为单个事务,以便在执行此操作时不会修改表 我需要使用事务处理吗?是否有单一的查询解决方案 是的,您需要使用事务。不能在单个查询中删除和选择行(即,无法“返回”或“选择”已删除的行) 您不一定需要执行
可重复读取
选项-我相信您也可以选择行进行更新
,尽管这是更高级别的锁定<代码>可重复读取似乎是安全执行此事务所需的最低锁定级别。它恰好是InnoDB的默认值
这对表的影响程度取决于wee
列上是否有索引。如果没有它,我相信MySQL将不得不锁定整个表
进一步阅读:
根据某些条件选择一些行,对数据执行一些操作,然后以原子方式删除这些行,也就是说,不删除任何符合条件但在选择
之后插入的行
与其他答案相反,可重复阅读
不够。提到请特别注意此标注:
数据库状态的快照适用于事务中的SELECT
语句,而不一定适用于DML语句。如果插入或修改某些行,然后提交该事务,则从另一个并发的可重复读取事务发出的DELETE
或UPDATE
语句可能会影响那些刚刚提交的行,即使会话无法查询它们
你可以自己试试:
首先创建一个表:
CREATE TABLE x (i INT NOT NULL, PRIMARY KEY (i)) ENGINE = InnoDB;
启动事务并检查表(现在称为会话1):
启动另一个会话(会话2)并插入一行。注意:此会话处于自动提交模式
您将看到新插入的行。然后再次回到第1课时:
SELECT * FROM x;
DELETE FROM x;
COMMIT;
第2次会议:
SELECT * FROM x;
您将看到,即使您在会话1中的SELECT
中没有得到任何结果,您还是删除了一行。在第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)
这个测试是用MySQL 5.5.12完成的
寻找正确的解决方案
使用SERIALIZABLE
事务隔离级别。但是请注意,会话2将阻塞插入
似乎SELECT…FOR UPDATE
也会起作用。我还没有100%深入地学习手册来理解这一点,但当我尝试它时,它起了作用。优点是您不必更改事务隔离级别。同样,会话2将阻塞插入
分别删除选择后的行。基本上,您必须在选择中包含一个唯一的列(主键会很好),然后使用从x中删除,其中i在(…)
,或者类似的东西,其中中的包含选择
结果集中的键列表。优点是您根本不需要使用事务,会话2在任何时候都不会被阻止。缺点是您有更多的数据要来回发送到SQL server。另外,我不知道单独删除行是否与使用与原始SELECT
相同的WHERE
子句一样有效,但是如果原始SELECT
的WHERE
子句复杂或缓慢,则单独删除可能会更快,因此这可能是另一个优势
编辑说,这是非常危险的事情之一,即使有文档记录,它几乎可以被认为是一个“错误”。但是,嘿,MySQL的设计者没有问我(或者其他任何人,显然)。你可以将行选择到一个临时表中,然后使用与选择相同的标准删除。由于SELECT FROM WHERE FOR UPDATE还返回一个结果集,因此您可以将SELECT FOR UPDATE更改为SELECT INTO tmp_表格以进行更新。然后使用原始条件或使用临时表中的数据作为条件删除选定的行
类似这样的内容(但尚未检查语法)
现在,您的记录已从原始表中删除,但临时表中也有一个副本,您可以保留或删除该副本。delete查询本身根据where
子句选择行。那么您还可以期待什么呢。但是我可以在一个行结果中获得select行吗?@user157195 select语句将返回多少行?小心——这个解决方案是错误的。请参考我的答案。另外,在回答你自己的问题时,最好是
SELECT * FROM x;
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)
START TRANSACTION;
SELECT a,b into TMP_TABLE FROM table_a WHERE a=1 FOR UPDATE;
DELETE FROM table_a
USING table_a JOIN TMP_TABLE ON (table_a.a=TMP_TABLE.a, table_a.b=TMP_TABLE.b)
WHERE 1=1;
COMMIT;