在Node.js中处理回滚的MySQL事务

我正在处理一个两三天的问题,我真的希望你能帮助我。

这是一个基于node.js的API,使用MySQL sequelize

在某些API调用中,代码会启动locking某些表的SQL事务,如果我同时向API发送多个请求, LOCK_WAIT_TIMEOUT得到LOCK_WAIT_TIMEOUT错误。

 var SQLProcess = function () { var self = this; var _arguments = arguments; return sequelize.transaction(function (transaction) { return doSomething({transaction: transactioin}); }) .catch(function (error) { if (error && error.original && error.original.code === 'ER_LOCK_WAIT_TIMEOUT') { return Promise.delay(Math.random() * 1000) .then(function () { return SQLProcess.apply(self, _arguments); }); } else { throw error; } }); }; 

我的问题是,同时运行的请求长时间相互locking,并且我的请求在很长一段时间(约60秒)之后返回。

我希望我能解释清楚和可以理解的,你可以给我提供一些解决办法。

这可能不是你的问题的直接答案,但也许通过看看你为什么有这个问题也将有所帮助。

1)doSomething()是做什么的? 无论如何,我们可以在那里做一些改进?

首先,需要60秒的交易是可疑的。如果你长时间locking一张桌子,那么很可能会重新devise这个devise。 给定一个典型的数据库操作运行10 – 100毫秒。

理想情况下,所有的数据准备应该在事务之外完成,包括从数据库读取的数据。 而交易应该只针对交易操作。

2)是否有可能使用MySQL存储过程?

没错,MySQL的存储过程没有被编译,就像Oracle的PL / SQL一样。 但它仍然在数据库服务器上运行。 如果你的应用程序真的很复杂,并且包含了大量的后台数据库和你的节点应用程序之间的networkingstream量,并且考虑到有这么多的javascript调用,它确实会减慢速度。 如果1)不节省你很多时间,可以考虑使用mysql存储过程。

显然,这种方法的缺点是在nodejs和mysql中维护代码比较困难。

如果1)和2)肯定是不可能的,你可以考虑某种stream量控制或排队工具。 要么你的应用程序确保第二个请求没有去,直到第一个完成,或者你有一些第三方排队工具来处理。 看来你不需要任何并行性来运行这些请求。

造成死锁的主要原因是数据库devise不佳。 如果没有关于数据库devise的进一步信息,以及哪些确切的查询可能会或可能不会彼此locking,就不可能为您的问题提供具体的解决scheme。

不过,我可以给你一个一般的build议/方法来解决这个问题:

  • 我会确保你的数据库至less规范化为第三范式 ,如果还不够的话。 可能有工具可以为你自动化这个过程。

    除了减less死锁的可能性,这也有助于保持数据的一致性,这总是一件好事。

  • 保持您的交易尽可能苗条。 如果您将新行插入到表中并相应地更新其他表,则可能需要使用Trigger而不是其他SQL语句来执行此操作。 这同样适用于读取行和值。 这些事情可以在交易之前或之后完成。
  • select正确的隔离级别 。 可能的隔离级别是:

    READ_UNCOMMITTED
    READ_COMMITTED
    REPEATABLE_READ
    SERIALIZABLE

    Sequelize 官方文档介绍了如何设置隔离级别并自行locking/解锁事务。

正如我所说,没有进一步的了解你的数据库和查询devise,我现在可以为你做的。
希望这可以帮助。