【问题标题】:Sybase deadlock executing stored procedure that inserts record if not presentSybase死锁执行存储过程,如果不存在则插入记录
【发布时间】:2015-04-27 14:06:19
【问题描述】:

我将 Oracle Coherence 与 sybase 表一起用作数据的后备存储。 我的 java 程序将数据插入到 coherence 缓存中,然后通过存储过程将数据写入表中。

批量记录的代码调用存储过程如下所示

 begin
 beging tran

 update tableA
 set 
      col1=val1,
      col2=val2
 where
      col3=val3

 if(@@rowcount=0)
 insert into tableA
 (
       col1,
       col2,
       col3
 )
 values
 (
       val1,
       val2,
       val3
 )

 if(@@error=0)
 begin
      rollback tran
 end

 commit tran
 end

近 50 个线程可以通过调用 execureBatch 来调用该过程,其中一个批处理包含近 125 条记录,但是所有记录相互不同,并且表得到了数据行锁定。

但是通过 BatchUpdateException 获得死锁错误

 java.sql.BatchUpdateException: Your server command (family id #0, process id #464) encountered a deadlock situation. Please re-run your command.

这里出现死锁的原因是什么?

【问题讨论】:

    标签: java sap-ase database-deadlocks oracle-coherence


    【解决方案1】:

    很可能,tableA 正在使用默认的所有页锁定,并且在索引页和数据页之间发生了死锁。但唯一确定的方法是启用 Sybase ASE 配置设置“打印死锁信息”,然后查看 ASE 错误日志文件中记录的内容。

    顺便说一句,执行回滚的测试“if(@@error=0)”看起来很有趣。如果@@error = 0,这将回滚。但这实际上意味着前面的语句运行良好并且没有错误,因此通常您会提交而不是回滚。 另一个问题是这并不像您期望的那样工作。在执行第一个 'if' 语句 '(@@rowcount=0)' 后,@@error 值将被重置为 0,因为 'if' 语句总是成功的。这意味着您将永远无法从更新中捕获错误状态。正确的做法是在单个语句中将@@rowcount 和@@error 直接复制到DML 语句之后的局部变量中,然后根据需要执行任何测试。

    最后,使用 'if' 而不使用 'begin-end' 复合语句是危险的,因为它会很快导致代码无法达到您的预期。作为一般原则,最好始终在 'if'、'else' 和 'while' 之后使用 begin-end。

    【讨论】:

    • 感谢您回复 RobV。 if(@@error=0) 是一个错字,实际上只是 (@@error!=0)。但是我不确定你为什么说在执行'if'语句后@@error 将被重置为0。它不会执行i'nsert into'语句并且结果将存储在@@error 中吗?
    猜你喜欢
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-28
    • 2014-04-04
    相关资源
    最近更新 更多