锁定选择

时间:2016-01-08 22:49:50

标签: mysql multithreading

我为所有表使用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操作,而且很糟糕。

这样做的最佳方法是什么?另外,我已经读过最后一个查询应该在事务中使用回滚而不是提交 - 为什么会这样?

1 个答案:

答案 0 :(得分:0)

如果想要长时间运行SELECT的InnoDB表的一致视图,最好的方法是确保当REPEATABLE READSELECT时,会话的事务隔离级别设置为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更改,我认为ROLLBACKCOMMIT是等效的。在这两种情况下,事务获得的所有锁都将被释放。就数据库而言,我认为它不会有所作为。

我认为这个建议来自客户端的首选模式。除非您已经应用了DML更改" ,否则可能存在遵循"不提交等规则的概念。但这只是猜测。

我个人的建议是遵循使用ROLLBACK结束交易的规范模式。我不赞成使用隐式ROLLBACK。在我个人看来,当我们想要明确地放弃已在事务中应用的DML更改时,应该发出{{1}}。而且这通常是由于异常或错误情况造成的。