我必须为非常高流量的Web应用程序编写SQL事务,该应用程序使用Postgres作为数据库。
我的问题是如果两个用户同时进行该事务,如何控制READ THEN UPDATE THEN WRITE事务的并发性?
对于流量非常高的Web应用程序,最佳做法是什么?任何帮助/建议都将非常感激。
提前致谢。
答案 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