在Knex中手动锁定表

时间:2018-09-14 06:01:21

标签: knex.js

我有一个表,当向其中添加新行时,所有现有行都需要更新。本质上,在一个“插入”完成之前,我不想允许另一个“插入”进行。

因此,我想普通的行级锁定或读取锁定是不够的,并且想在事务期间直接锁定表。

有没有办法在Knex中手动锁定表(以ACCESS EXCLUSIVE模式)?

我的猜测是这将涉及:

  1. 运行原始sql(锁定和解锁)并确保相同

  2. 连接用于事务。

有没有办法做到这一点?或者我有更好的解决方案来解决我的问题。

p.s。我正在探索的另一种方法是使用作业队列,并让单个工作人员插入记录(使用原始sql连接)。但有人告诉我这在多节点方案中不起作用。

3 个答案:

答案 0 :(得分:1)

您可以为此使用数据库锁,例如mysql中的GET_LOCK

具体来说,您可以在knex中使用事务,以确保您可以使用特定的连接, 或者您可以使用acquireConnection并将连接设置为GET_LOCK查询。

http://knexjs.org/#Builder-connection

示例:

let conn;
try {
  conn = await knex.client.acquireConnection();

  try {
    let lockRes = await knex.select(knex.raw('GET_LOCK(?, ?) as res', ['lock_name', 15])).connection(conn);

    if (!lockRes.length || lockRes[0]['res'] !== 1) {
      // Did not acquire lock
      return;
    }

    // Your code here
  }
  finally {
    await knex.select(knex.raw('RELEASE_LOCK(?)', ['lock_name'])).connection(conn);
  }
}
finally {
  conn && await knex.client.releaseConnection(conn);
}

答案 1 :(得分:0)

使用knex,您当前无法选择将连接查询发送到的位置,除非您正在使用事务。发送到同一事务的所有查询也将发送到同一连接。

要发送锁定命令,需要使用knex.raw

  1. 开始交易
  2. 将原始SQL锁定查询发送到事务
  3. ???
  4. 利润

如何精确完成锁定取决于您使用的数据库。通常,提交事务后会自动释放锁。

答案 2 :(得分:0)

如果您使用MySQL,那是根本不可能的,因为knex不允许您选择要使用的连接。确保两个特定查询在相同的连接池中执行的唯一方法是将它们嵌套在knex事务中。但是MySQL文档说:

  

LOCK TABLES不是事务安全的,并且隐式提交任何活动   尝试锁定表之前进行事务处理。

如果您的数据库驱动程序是Postgres,而不是MySQL,则将LOCK TABLE查询放入事务中确实可以。