postgresql - SKIP LOCKED 除非所有行都被锁定

标签 postgresql locking

有没有办法使用SKIP LOCKED对 PostgreSQL 进行查询,以避免行已被锁定,但同时如果所有内容都已锁定以等待第一个解锁行?

在我的用例中,我希望避免在请求可用电话号码时出现误报。但在我锁定所有号码的情况下,不太可能,但它仍然可能发生,应该解决。

SELECT plain_number FROM pool
  ORDER BY RANDOM()
  LIMIT 1
  FOR UPDATE
  SKIP LOCKED

最佳答案

这似乎有效:

WITH sl AS (
  SELECT plain_number FROM pool ORDER BY random() LIMIT 1 FOR UPDATE SKIP LOCKED
),
fu AS (
  SELECT plain_number FROM pool WHERE NOT EXISTS(SELECT 1 FROM sl) ORDER BY random() LIMIT 1 FOR UPDATE
)
SELECT * FROM sl FULL JOIN fu USING (plain_number);

但是,它会等待随机的 plain_number 来释放其锁定。我认为不可能等待第一个锁被释放。

设置:

create table pool(
  plain_number text primary key
);

insert into pool(plain_number)
select generate_series(1, 9)::text;

这是我为测试编写的一个小node.js 脚本:

const pg = require("pg");
const options = {
    "user": "test",
    "password": "test",
    "database": "test"
};

function thread_ish() {
    const client = new pg.Client(options);
    const end = client.end.bind(client);
    const rollback = function (client) {
        client.query("ROLLBACK", end);
    };

    client.connect(function () {
        client.query("BEGIN", function (err) {
            if (err) {
                console.error(err);
                return rollback(client);
            }
            client.query(
                "WITH sl AS ("
                + "  SELECT plain_number FROM pool ORDER BY random() LIMIT 1 FOR UPDATE SKIP LOCKED"
                + "), fu AS ("
                + "  SELECT plain_number FROM pool WHERE NOT EXISTS(SELECT 1 FROM sl) ORDER BY random() LIMIT 1 FOR UPDATE"
                + ")"
                + "SELECT * FROM sl FULL JOIN fu USING (plain_number)",
                function (err, result) {
                    if (err) {
                        console.error(err);
                        return rollback(client);
                    }

                    console.log("Selected number is", result.rows);
                    setTimeout(function () {
                        client.query("COMMIT", end);
                    }, 1000);
                }
            );
        });
    });
}

for (var i = 0; i < 13; ++i) {
    setTimeout(thread_ish, Math.random() * 100);
}

关于postgresql - SKIP LOCKED 除非所有行都被锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43331442/

相关文章:

c++ - 为什么 std::condition_variable 的通知和等待函数都需要一个锁定的互斥量

SQL 原子增量和锁定策略 - 这安全吗?

arrays - 将数组从node-postgres传递到plpgsql函数

sql - 如何正确索引多对多关联表?

sql - 在 SQL Server 和 Postgresql 中将 CASE 用于类似枢轴的函数

Powershell 脚本无法删除目录

postgresql - 将 Postgres 对象添加到 Template1

python - Django 和 Postgres 中为 select_for_update 生成的查询顺序的差异

PHP 下载会阻止其余请求

jpa - 用于应用程序同步的数据库锁