在Postgres中控制READ THEN UPDATE THEN WRITE事务的并发性

时间:2015-09-06 19:57:31

标签: postgresql

我必须为非常高流量的Web应用程序编写SQL事务,该应用程序使用Postgres作为数据库。

我的问题是如果两个用户同时进行该事务,如何控制READ THEN UPDATE THEN WRITE事务的并发性?

对于流量非常高的Web应用程序,最佳做法是什么?任何帮助/建议都将非常感激。

提前致谢。

1 个答案:

答案 0 :(得分:5)

解释性说明:我假设你的意思是read-modify-write工作负载,并且“READ THEN UPDATE THEN WRITE”的大写字母并不是用来表示产品的某些特殊事务选项SQL语法我不熟悉。

如果您的webapp正在执行具有高并发性和流量的读 - 修改 - 写周期,那么您就无法使用传统的行锁定:

  • BEGIN
  • SELECT primarykey, col1 FROM thetable WHERE ... FOR UPDATE
  • 申请中的流程
  • UPDATE blah SET col1 ... WHERE primarykey ...
  • COMMIT

因为用户“思考时间”和网络延迟可能无限制。您的大多数连接将在“应用程序”阶段中无限期地停留。每个等待会话意味着一个开放的空闲事务,这意味着有限的数据库资源,如连接限制和消耗的内存。

传统的,完善的解决方案是使用optimistic concurrency control,有时误导性地称为乐观锁定。一些ORM原生支持这一点。如果您直接使用SQL或通过不使用的框架,这很容易实现。原则是你的逻辑流看起来更像是这样:

  • BEGIN READ ONLY TRANSACTION
  • SELECT primarykey, col1, row_version FROM thetable WHERE ...
  • COMMIT
  • 应用程序中的进程并等待用户响应
  • BEGIN
  • UPDATE blah SET col1 ..., row_version = row_version + 1 WHERE primarykey ... AND row_version = 'prev_row_version'
  • 使用UPDATE响应中数据库返回的受影响的行计数检查UPDATE是否影响了任何行
    • 如果它影响零行,则WHERE子句不匹配,表示其他人更新了该行,因为我们SELECT编辑了它。回到开始并重新开始。
    • 如果它影响了一行,我们知道没有其他人打败我们更新此行,所以COMMIT告诉用户一切正常。

像Hibernate这样的框架通过将列注释为行版本来自动支持它。

乐观并发控制可以通过适当的数据库触发器与传统锁定进行互操作。见,例如, the sample trigger I wrote for Hibernate inter-operation