PostgreSql 中的事务

Transaction in PostgreSql

我想在 java 的 PosgreSql 中实现以下场景:

我希望在交易期间其他用户无法使用数据。如果当其他用户尝试更新 table.

时出现异常就足够了

我试过使用 select for updateselect for share,但它也会锁定数据以供读取。我尝试使用 lock 命令,但我无法获得锁定 (ERROR: could not obtain lock on relation "fppo10") 或另一个事务在尝试提交事务时获得锁定,而不是在更新数据时获得锁定。

是否存在一种在事务开始时锁定数据以防止任何其他调用 updateinsertdelete 语句的方法?

这个场景在 DB2 数据库上成功运行了几年。现在我需要同样的应用程序也适用于 PostgreSql。

而不是 select for update 尝试 "row exclusive" table 锁:

LOCK TABLE YourTable IN ROW EXCLUSIVE MODE;

根据documentation,这把锁:

The commands UPDATE, DELETE, and INSERT acquire this lock mode on the target table (in addition to ACCESS SHARE locks on any other referenced tables). In general, this lock mode will be acquired by any command that modifies data in a table.

请注意锁的名字很混乱,但它确实锁定了整个table:

Remember that all of these lock modes are table-level locks, even if the name contains the word "row"; the names of the lock modes are historical

终于,我想我明白你的意思了。
这本身不是 "transaction" 问题(并且根据要处理的表的数量和所需的语句,您甚至可能不需要一个),它是一个 应用程序设计 问题。你有两种通用的方法来处理这个问题;乐观和悲观锁定。

悲观锁定是显式获取和持有锁。当您可以保证您 更改行以及与之相关的内容时,以及您的事务将 时,最好使用它。您可以在向帐户添加销售时更新 "current balance" 等情况下使用它,一旦购买完成(更新将会发生,交易持续时间很短,因为此时没有进一步的选择)。如果用户读取一行然后去吃午饭(或休假......),悲观锁定会变得令人沮丧。

乐观锁定正在读取一行(或一组),并且采用任何类型的db-layer锁。如果您只是阅读行,没有立即更新其中任何一个的计划,则最好使用它。通常,行数据将包含一个 "version" 值(递增的计数器或上次更新的时间戳)。如果您的应用程序要更新行,它会先比较数据的原始值以确保它没有被其他东西更改,并在数据更改时提醒用户。大多数与用户交互的应用程序应该使用乐观锁定。但是,它确实要求用户注意并注意更新的值。

请注意,由于在乐观锁定中很少(并且在很短的时间内)使用锁,因此它通常不会与使用悲观锁的单独进程发生冲突。悲观的锁定应用程序会阻止乐观的应用程序更新锁定的行,但不会读取它们。
另请注意,这通常不适用于批量更新,批量更新几乎没有用户交互(如果有的话)。


tl;博士

不要在读取时锁定行。只需将旧值与应用程序上次读取的值进行比较,如果不匹配则拒绝更新(并提醒用户)。训练您的用户做出适当的回应。