如何在不传输数据的情况下使用 select 获取 DB2 中的锁以进行更新?

How to obtain a lock in DB2 with select for update without transferring data?

通过大量实验我发现

(jdbcTemplate is a JdbcTemplate 只是用来方便执行查询。它与问题没有实际关系)

jdbcTemplate.query(
    "select 0 from example where id = 23 for update with rs use and keep update locks", 
    rs -> {
        rs.next();
        return null;
});

获得对 selected 行的锁定,而这一行没有:

jdbcTemplate.query(
    "select 0 from example where id = 23 for update with rs use and keep update locks", 
    rs -> {
        return null;
});

出于同样的原因,我假设以下未获得锁定:

jdbcTemplate.execute(
    "select id from example where id = 23 for update with rs use and keep update locks"
);

我有一个分为两部分的问题:

  1. 这到底是怎么回事?
  2. 我如何在数据库中执行 select 更新以便它确实导致锁定,但不会导致每个 select 行的 return 数据?也许是某种脚本?

There is a Github repository testing these (and many more variants)

Read Stability (RS) 隔离级别文档中的引用:

The read stability isolation level locks only those rows that an application retrieves during a unit of work.

-- Rows are locked / accessed during "fetch"
select * from example where id = 23 with rs use and keep update locks;

-- Rows must be accessed either during "execute" / "open" or "fetch" to get the corresponding result
select count(1) from example where id = 23 with rs use and keep update locks;

实现RS的主要要求换句话说:如果某行参与了该语句的第一次调用的结果,那么它必须参与该语句的每次后续调用的结果具有相同值的相同语句。

当您只有 select 行时,它们仅在 fetch 期间被检索(访问)。在您获取它们之前,它们不会被访问。无需事先锁定这些行即可实现上述逻辑目标。为什么要降低系统并发性,如果您可以 "lazy" 获取/锁定所需的行?

但是当您对所需的行进行一些聚合时,必须在 execute / open 期间或在第一 fetch 期间访问它们(并且唯一的 fetch, 因为它是聚合) 来锁定相应的行。我相信,这种行为没有记录 - 它只是当前观察到的行为。

为了安全起见,我建议您无论如何都对聚合语句执行 1 fetch。没有人可以保证(除非您就此询问 IBM 支持并获得相应的说明),这样的行为将来可能不会改变。