我为所有表使用InnoDB引擎。我知道默认情况下INSERT会为要插入的行创建锁定,UPDATE会为它使用的行创建锁定(无论是在set还是where clausules)。 SELECT不会锁定任何东西。没有什么可以锁定整个表格。
但是,如果我做了类似的事情,该怎么办?
SELECT * FROM table INTO OUTFILE '/tmp/file.txt'
如果它持续5分钟,任何其他线程都可能发生任何事情。我读过我可以使用:
SELECT * FROM table INTO OUTFILE '/tmp/file.txt' LOCK IN SHARE MODE;
但是我又不能在这张桌子上做任何SELECT操作,而且很糟糕。
这样做的最佳方法是什么?另外,我已经读过最后一个查询应该在事务中使用回滚而不是提交 - 为什么会这样?
答案 0 :(得分:0)
如果想要长时间运行SELECT的InnoDB表的一致视图,最好的方法是确保当REPEATABLE READ
为SELECT
时,会话的事务隔离级别设置为SELECT
运行
它不会阻止尝试读取相同行的其他线程。但是它可能阻止某些线程获得独占锁或写意图锁。
https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html
作为附录,澄清OP提出的一些观点。
" SELECT不会锁定任何内容。"
非锁定 SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE
无法获得行锁,确实如此。但是一些特殊的SELECT语句(如后所述)可以获得行锁:
ALTER TABLE
还有元数据锁,它会在SELECT
语句执行时阻止表上的DDL操作(例如LOCK TABLE
)。
"没有什么可以锁定整个表格。"
这不完全正确。 SELECT ... FOR UPDATE
语句可以获取整个表的锁定。并且READ UNCOMMITED
(没有谓词)可以(可能)获取表中每一行的锁。
" SELECT ... LOCK IN SHARE MODE将阻止其他SELECT语句"
这不是真的。共享锁将阻止来自其他线程的独占锁。但是他们不会阻止其他线程获取共享锁,并且不会阻止非锁定的SELECT语句。
这样做的最佳方法是什么?
再次重新迭代我的答案的第一部分......只需运行一个非锁定的SELECT语句。只要事务隔离级别未设置为ROLLBACK
,SELECT语句将从SELECT开始执行时的时间点获得表中行的一致视图。
另外,我已经读过最后一个查询应该在事务中使用回滚而不是提交 - 为什么会这样?
这是一个奇怪的概念。让我感到困惑。为什么COMMIT
优先于COMMIT
?
只要没有应用DML更改,我认为ROLLBACK
和COMMIT
是等效的。在这两种情况下,事务获得的所有锁都将被释放。就数据库而言,我认为它不会有所作为。
我认为这个建议来自客户端的首选模式。除非您已经应用了DML更改" ,否则可能存在遵循"不提交等规则的概念。但这只是猜测。
我个人的建议是遵循使用ROLLBACK
结束交易的规范模式。我不赞成使用隐式ROLLBACK
。在我个人看来,当我们想要明确地放弃已在事务中应用的DML更改时,应该发出{{1}}。而且这通常是由于异常或错误情况造成的。