使用 Seam & 重试事务的最佳方式休眠
我有一个与 Seam & 一起使用的 Seam Web 应用程序。 Hibernate(从 JDBC 到 SQLServer)。
它运行良好,但在重负载下(使用 JMeter 进行压力测试),我遇到了一些 LockAcquisitionException
或 OptimisticLockException
。
LockAquisitionException
是由 SQLServerException
“事务(进程 ID 64)在锁资源上与另一个进程发生死锁,并已被选为死锁受害者。重新运行事务”。
然后,我编写了一个 Seam 拦截器来重新运行 LockAquisitionException
的此类事务:
@AroundInvoke
public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {
if (instanceThreadLocal.get() == null && isMethodInterceptable(invocationContext)) {
try {
instanceThreadLocal.set(this);
int i = 0;
PersistenceException exception = null;
do {
try {
return invocationContext.proceed();
} catch (final PersistenceException e) {
final Throwable cause = e.getCause();
if (!(cause instanceof LockAcquisitionException)) {
throw e;
}
exception = e;
i++;
if (i < MAX_RETRIES_LOCK_ACQUISITION) {
log.info("Swallowing a LockAcquisitionException - #0/#1", i, MAX_RETRIES_LOCK_ACQUISITION);
try {
if (Transaction.instance().isRolledBackOrMarkedRollback()) {
Transaction.instance().rollback();
}
Transaction.instance().begin();
} catch (final Exception e2) {
throw new IllegalStateException("Exception while rollback the current transaction, and begining a new one.", e2);
}
Thread.sleep(1000);
} else {
log.info("Can't swallow any more LockAcquisitionException (#0/#1), will throw it.", i, MAX_RETRIES_LOCK_ACQUISITION);
throw e;
}
}
} while (i < MAX_RETRIES_LOCK_ACQUISITION);
throw exception;
} finally {
instanceThreadLocal.remove();
}
}
return invocationContext.proceed();
}
第一个问题:您认为这个拦截器会正确完成这项工作吗?
通过谷歌搜索并看到 <一个href="http://www.koders.com/java/fid249E28267D98E75C62D00C627BCB92D6FD888F82.aspx?s=hibernate#L43" rel="nofollow">户外 (此处有论坛讨论),博尼塔 和 Orchestra 也有一些方法来重新运行此类事务,并且它们捕获更多的异常,例如 StaleObjectStateException
例如(我的 OptimisticLockException 的原因)。
我的第二个问题如下:对于 StaleObjectStateException
(“行已被另一个事务更新或删除(或未保存的值映射不正确)”),通常你不能只是重新运行事务,因为这是与数据库和 @Version 字段同步的问题,不是吗?例如,为什么 Alfresco 会尝试重新运行由此类异常引起的此类事务?
编辑 :
对于由SQLServerException
引起的LockAcquisitionException
,我查看了网络上的一些资源,即使我应该仔细检查我的代码,似乎它仍然可能发生。 ..以下是链接:
- 一篇关于该主题的文章(带有 评论说这也可能因资源耗尽而发生)
- 另一篇带有子链接的文章:
甚至微软也表示“尽管死锁可能是最小化,它们无法完全避免,这就是为什么前端应用程序应该设计为处理死锁。”
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
实际上,我终于找到了如何避免著名的“事务(进程 ID 64)与另一个进程在锁资源上发生死锁,并已被选为死锁受害者。重新运行事务”。
所以我不会真正回答我的问题,但我会解释我所看到的以及我如何做到这一点。
起初,我认为我遇到了“锁升级问题”,它会将我的行锁转换为页锁并产生死锁(我的 JMeter 测试运行在一个场景中,该场景在选择行时进行删除/更新,但删除和更新不会不一定涉及与选择相同的行)。
所以我读了 SQL2005 中的锁定升级以及如何解决所导致的阻止问题通过 SQL Server 中的锁升级(由 MS),最后使用 sp_lock 诊断 SQL Server 性能问题。
但在尝试检测我是否处于锁定升级情况之前,我进入了该页面: http://community .jboss.org/message/95300。它谈到了“事务隔离”,并且SQLServer有一种特殊的隔离,称为“快照隔离”。
然后我发现 将快照隔离与 SQL Server 和 Hibernate 结合使用 并阅读 使用快照隔离(由 MS)。
所以我首先在我的数据库上启用了“快照隔离模式”:
然后我必须将 JDBC 驱动程序的事务隔离定义为
4096
...并阅读“Hibernate in Action”一书的“5.1 段” .6 设置隔离级别”,内容如下:所以我读了配置 JDBC 数据源(适用于 JBoss 4) 最后编辑了我的
database-ds.xml
文件来添加以下内容:当然,最重要的部分是
<事务隔离>4096
。然后,我就不再遇到僵局问题了! ...所以我的问题现在对我来说或多或少毫无用处...但也许有人可以有真正的答案!
Actually I finally found how to dodge the famous "Transaction (Process ID 64) was deadlock on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction".
So I will not really answer my question but I will explain what I saw and how I manage to do that.
At first, I thought that I had a "lock escalation problem" which would transform my row locks into page locks and produce my deadlocks (my JMeter test runs on a scenario which does delete / update while selecting rows, but the deletes and updates don't concern necessarily the same rows as the selects).
So I read Lock Escalation in SQL2005 and How to resolve blocking problems that are caused by lock escalation in SQL Server (by MS) and finally Diagnose SQL Server performance issues using sp_lock.
But before trying to detect if I was in a lock escalation situation, I fall on that page : http://community.jboss.org/message/95300. It talks about "transaction isolation" and that SQLServer has a special one which is called "snapshot isolation".
I then found Using Snapshot Isolation with SQL Server and Hibernate and read Using Snapshot Isolation (by MS).
So I first enabled the "snapshot isolation mode" on my database :
Then I had to define transaction isolation for JDBC driver to
4096
... and by reading the book "Hibernate in Action" on paragraph "5.1.6 Setting an isolation level", it reads :So I read Configuring JDBC DataSources (for JBoss 4) and finally edited my
database-ds.xml
file to add this :The most important part is of course
<transaction-isolation>4096</transaction-isolation>
.And then, I got no more deadlock problem anymore ! ... so my question is now more or less useless for me ... but perhaps someone could have a real answer !