在存储过程中,我具有以下简单的两次选择序列:
SELECT * FROM mytable WHERE <conditions>;
SELECT id FROM mytable ORDER BY id DESC LIMIT 1;
其中 id 是 mytable 的主键。
总体目的是从 mytable 中选择一些行(包括最新的行-即具有最大 id 值的行),然后选择第二行,获取同一表中最后/最新行的 id 。
问题:如何确保在第一选择和第二选择之间没有新记录插入?
我要使用:
TRANSACTION
select <1..> FOR UPDATE;
select <2..>;
COMMIT
但是这将始终有效并且有更好的方法吗?
还是可以做一些不同的事情来实现从第一个选择中获得最大的 id 值而无需第二个选择的目的?
答案 0 :(得分:0)
如果您尚未更改隔离级别,则使用默认的REPEATABLE READ
,它已经解决了此问题。
要检查您使用的隔离级别,可以执行以下查询:
SELECT @@global.tx_isolation, @@session.tx_isolation;
全局值是新创建的会话的默认值。会话值当然是您当前正在使用的值。
您可以使用以下方式为会话进行显式设置
SET SESSION tx_isolation='REPEATABLE-READ';
使用REPEATABLE-READ
,您可以简单地执行以下操作:
START TRANSACTION;
SELECT * FROM mytable WHERE <conditions>;
SELECT id FROM mytable ORDER BY id DESC LIMIT 1;
COMMIT;
在您进行2次选择时,另一个会话在表中插入行时,该行将不会显示在您的事务中。
我在答案here中发布了有关隔离级别的更多详细信息。
如果要将两个查询合并为一个,可以执行以下操作:
SELECT m.*, s.maxid
FROM mytable m
CROSS JOIN (SELECT MAX(id) AS maxid FROM mytable) s
WHERE <conditions>;