试图理解为什么 @transactional(noROllBackFor .... 不起作用
Trying to understand why @transactional(noROllBackFor .... is not working
我有一些代码如下所示:
@Transactional(noRollbackFor = { CannotAcquireLockException.class, LockAcquisitionException.class })
public void deleteSomeData() {
int backOffTime = 0;
int fibonacci = 1;
boolean executed = false;
do {
try {
this.myDAO.deleteTheData();
executed = true;
} catch (RuntimeException rt) {
int newBackoffTime = backOffTime + fibonacci;
fibonacci = backOffTime;
backOffTime = newBackoffTime;
try {
Thread.sleep(backOffTime * 100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} while (!executed);
}
这是在 Spring/JPA 环境中 运行ning。该代码由许多 Quartz 驱动的任务 运行 组成,这些任务在不同时间触发,有时同时触发。因此,如果抛出死锁异常,我试图通过在延迟后重新执行更新代码来解决数据库 (MySQL) 死锁。
我一直在尝试各种各样的事情并阅读了很多关于事务、死锁等的帖子
问题是,如果 this.myDAO.deleteTheData();
抛出 CannotAcquireLockException
,则事务被标记为需要回滚。我正在尝试做的是等待一段时间,然后再次尝试更新。然而,第二次尝试由于回滚状态而失败。因此,如果抛出此异常,我试图停止将事务设置为需要回滚。
我不确定我的头脑是否完全正确,而且这段代码无法正常工作。该事务仍被标记为需要回滚。
我可以将循环代码移到调用此方法的代码中,这将消除对事务的担忧,但是这将涉及大量重复代码执行,我想保留它尽可能靠近数据库。
关于我哪里出错了有什么建议吗?
阅读我原来的 post 上的答案后,我改用 Spring Retry 并且能够删除我所有的循环代码。该方法现在看起来像这样:
@Transactional
@ConcurrentDBUpdateRetryPolicy
public void deleteSomeData() {
this.myDAO.deleteTheData();
}
使用定义我要使用的重试策略的自定义注释。您不需要执行自定义注释,但以这种方式执行它可以让您集中一个通用的重试定义。这是自定义注释:
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Retryable(
include = CannotAcquireLockException.class,
maxAttempts = 10,
backoff = @Backoff(delay = 500, maxDelay = 10000, multiplier = 2, random = true)
)
public @interface ConcurrentDBUpdateRetryPolicy {}
到目前为止,这一切都非常顺利。所以感谢提出建议的人,感谢 Spring Retry.
的作者
我有一些代码如下所示:
@Transactional(noRollbackFor = { CannotAcquireLockException.class, LockAcquisitionException.class })
public void deleteSomeData() {
int backOffTime = 0;
int fibonacci = 1;
boolean executed = false;
do {
try {
this.myDAO.deleteTheData();
executed = true;
} catch (RuntimeException rt) {
int newBackoffTime = backOffTime + fibonacci;
fibonacci = backOffTime;
backOffTime = newBackoffTime;
try {
Thread.sleep(backOffTime * 100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} while (!executed);
}
这是在 Spring/JPA 环境中 运行ning。该代码由许多 Quartz 驱动的任务 运行 组成,这些任务在不同时间触发,有时同时触发。因此,如果抛出死锁异常,我试图通过在延迟后重新执行更新代码来解决数据库 (MySQL) 死锁。
我一直在尝试各种各样的事情并阅读了很多关于事务、死锁等的帖子
问题是,如果 this.myDAO.deleteTheData();
抛出 CannotAcquireLockException
,则事务被标记为需要回滚。我正在尝试做的是等待一段时间,然后再次尝试更新。然而,第二次尝试由于回滚状态而失败。因此,如果抛出此异常,我试图停止将事务设置为需要回滚。
我不确定我的头脑是否完全正确,而且这段代码无法正常工作。该事务仍被标记为需要回滚。
我可以将循环代码移到调用此方法的代码中,这将消除对事务的担忧,但是这将涉及大量重复代码执行,我想保留它尽可能靠近数据库。
关于我哪里出错了有什么建议吗?
阅读我原来的 post 上的答案后,我改用 Spring Retry 并且能够删除我所有的循环代码。该方法现在看起来像这样:
@Transactional
@ConcurrentDBUpdateRetryPolicy
public void deleteSomeData() {
this.myDAO.deleteTheData();
}
使用定义我要使用的重试策略的自定义注释。您不需要执行自定义注释,但以这种方式执行它可以让您集中一个通用的重试定义。这是自定义注释:
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Retryable(
include = CannotAcquireLockException.class,
maxAttempts = 10,
backoff = @Backoff(delay = 500, maxDelay = 10000, multiplier = 2, random = true)
)
public @interface ConcurrentDBUpdateRetryPolicy {}
到目前为止,这一切都非常顺利。所以感谢提出建议的人,感谢 Spring Retry.
的作者