【问题标题】:SQL transactions run on Postgres 9.0 but one is aborted on SQLServer 2005SQL 事务在 Postgres 9.0 上运行,但在 SQLServer 2005 上中止了一个
【发布时间】:2012-11-12 14:21:55
【问题描述】:

假设我们尝试同时运行以下两个事务:

T1:
BEGIN
  UPDATE place
  SET state_code=5
  WHERE state_code=6
  AND type='town'
COMMIT

T2:
BEGIN
  UPDATE place
  SET state_code=6
  WHERE state_code=5
  AND type='town'
COMMIT

在 Postgres 9.0 上,事务成功完成。但是,当在 SQLServer 2005 T1 上运行时,T1 会中止,因此所有状态都以 state_code=5 结束。

  1. 哪个 DBMS 遵守/不遵守严格的事务序列化,为什么?
  2. 每个 DBMS 中可能设置或未设置哪些设置会导致此行为?

【问题讨论】:

  • 听起来像是家庭作业。
  • SQL Server 中的错误信息是什么?
  • 目前还不清楚预期的结果是什么。是否有转置价值观的意图?还是将它们设置为相同?这两种结果都可能在READ COMMITTEDSNAPSHOT 隔离中,具体取决于确切的执行顺序。

标签: sql sql-server postgresql serialization transactions


【解决方案1】:

MS SQL 使用事务语句:

BEGIN transaction
  UPDATE place
  SET state_code=5
  WHERE state_code=6
  AND type='town'
COMMIT

【讨论】:

  • 感谢您的回复,但这并没有真正的帮助。交易的语法无关紧要。
  • 您是否尝试在 MS SQL 上运行上述代码?因为在这种情况下你会得到一个错误
  • 问题测试理论。假设行为如上所述发生。
  • 那么我们需要更多信息来帮助您。你能用 MS SQL 代码 mybe 一些测试数据和表创建脚本来举例说明错误行为吗?
  • 对此的最佳答案是 POSTGRESQL 和 MSSQL 对事务有不同的语法,因此相同的代码无法运行您提供的代码适用于 POSTGRESQL 因为它包含其语法但无法运行MSSQL
【解决方案2】:

在 PostgreSQL 中,您可以通过使用表级锁来测试这一点,以确保竞争事务同时运行。设置:

CREATE TABLE place (id serial primary key, state_code integer, type text);
INSERT INTO place (state_code, type) VALUES (5, 'town'), (6, 'town');

然后在会话 T0 中:

BEGIN; LOCK TABLE place;

在两个新会话中发出 T1 和 T2 的命令。

现在回到 T0 问题:

ROLLBACK;

释放表级锁并允许 T1 和 T2 竞争。

READ COMMITTED 隔离(默认)中,两者都将被转置...尽管在现实世界中这将取决于事务的确切顺序并且不能依赖。

REPEATABLE READ 中(在PostgreSQL 9.0 中称为SERIALIZABLE 隔离),它们都将被转置,与READ COMMITTED 相同,因为两者对于单语句事务基本上是等效的;运行第一条语句时拍摄快照,而不是在BEGIN

SERIALIZABLE 隔离中,通过default_transaction_isolation GUC 或BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE 设置,一个事务将因序列化失败而无法提交,而另一个事务将成功,导致所有行具有state_code 5,或所有行具有state_code 6,取决于哪个交易赢了。

如果 SQL Server 也中止了其中一个事务,那么它正在执行正确的序列化。

SQL Server 遵循正确的序列化(当要求严格序列化时,就像当前版本的 PostgreSQL 一样),而 PostgreSQL 的测试版本设置为 READ COMMITTED 隔离(不应该序列化)或预9.1 的SERIALIZABLE 隔离(无法检测到此异常)并且遵守严格的事务序列化语义。

如果default_transaction_isolation 设置为除SERIALIZABLE 之外的任何值,则在 PostgreSQL 9.2 中可能会遇到这种情况,并且是 PostgreSQL 9.1 之前的规范。

看起来 SQL Server 使用了SET TRANSACTION ISOLATION LEVEL。在 PostgreSQL 中,您使用 default_transaction_isolation GUCSET TRANSACTION ISOLATION LEVEL。尚不清楚 SQL Server 是否允许您全局设置默认事务隔离级别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-02
    • 2013-02-22
    相关资源
    最近更新 更多