作为应用程序开发人员,我习惯于仅将数据库事务用作在用户单击“保存”后进行修改的一种方式。
这是我熟悉的大多数数据库服务器期望它们的事务被使用的方式,它们不喜欢长期事务。在许多情况下,它们会导致其他作者甚至读者无法处理此类阻塞。
但我只熟悉数据库世界的一部分——我主要使用 SQL Server 并且见过一些 MySQL。这些数据库主要用作应用程序存储,数据库本身的业务逻辑大多被简化为以一种或另一种方式生成唯一 ID。
我可以想象其他服务器,例如 Oracle,有不同的期望。
我感兴趣的方法是,当用户单击“编辑”时,会打开一个事务,并且用户所做的所有编辑都会立即发送到数据库。因此,所有业务逻辑都会立即应用,因此甚至在“保存”(又名“提交”)之前就可以在用户界面中看到。
这种范式将使几件事变得更容易:
- 进行编辑的应用程序不必像 ORM 那样管理未保存行的初步 id。
- 用户甚至可以在提交更改之前从数据库服务器中的业务逻辑获得反馈,例如计算列的值或触发器的结果效果。
- 如果在提交之前进行了大量更改,则可以在编辑的早期检测到约束违规。
- 如果数据库服务器对其有很好的支持,来自多个事务的冲突编辑可能会导致更好的错误消息,例如“用户 abc 正在编辑行 xyz”。
我已经调查了 SQL Server 对这种方法的支持状态,它即将成为可能,但在实践中通常可能是个坏主意。主要问题是即使在快照隔离下,那里的编写者也会相互锁定。特别是,先写的作者获胜,而不是先提交的作者。
我的问题是:是否有更好地支持这种场景的数据库服务器?例如,Oracle 对此有何评论?特别是,服务器必须
- 允许并发写入同一行而不会阻塞并让第一个提交者获胜。
- 因此,已写入的未提交的悬空事务根本不应该影响其他用户。如果另一个用户提交了一个应该可以工作的冲突写入,并且悬空事务只是变得不可提交(或者只是在那时自动回滚)。
我正在为我的通用数据库浏览器研究这个;
答案是否定的,Oracle 不支持这个,就像 SQL Server 一样。但是,正如现在已经多次指出的那样,客户端乐观并发是实现此行为的方式:如果另一个会话在读取该行后修改了该行,则每个写入器都会使用失败或影响零行的查询进行写入。
当用户单击编辑时启动事务并将其保持打开直到他保存是一个坏主意。如果用户让他的屏幕打开几个小时怎么办?
否则有很多方法可以处理。
例如,在我工作的应用程序中,开发人员做了以下工作:
UPDATE
的行WHERE LastSavedTimestamp=value
@@ROWCOUNT = 0
(这意味着该行同时被其他人更新。)他们向用户显示一条消息,说其他人修改了该行并且他们需要刷新屏幕。这只是一个例子。许多应用程序需要处理并发更新。我相信你可以在网上找到一些其他的例子。