title: Best way to retry a transaction with Seam & Hibernate
body: <p>I've got a Seam web application working with Seam &amp; Hibernate (JDBC to SQLServer).</p>
  
  <p>It's working well, but under heavy load (stress test with JMeter), I have some <code>LockAcquisitionException</code> or <code>OptimisticLockException</code>.</p>
  
  <p>The <code>LockAquisitionException</code> is caused by a <code>SQLServerException</code> <em>"Transaction (Process ID 64) was deadlock on lock resources with another process and has been chosen as the deadlock victim. <strong>Rerun the transaction</strong>"</em>.</p>
  
  <p>I've then written a Seam Interceptor to rerun such transactions for <code>LockAquisitionException</code> :</p>
  
  <pre class="lang-java prettyprint-override"><code>@AroundInvoke
  public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {
      if (instanceThreadLocal.get() == null &amp;&amp; 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 &lt; 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 &lt; MAX_RETRIES_LOCK_ACQUISITION);
  
              throw exception;
  
          } finally {
              instanceThreadLocal.remove();
          }
      }
      return invocationContext.proceed();
  }
  </code></pre>
  
  <p>First question : <strong>do you think this interceptor will correctly do the job ?</strong></p>
  
  <p>By googling around and saw that <a href="http://www.koders.com/java/fid249E28267D98E75C62D00C627BCB92D6FD888F82.aspx?s=hibernate#L43" rel="nofollow">Alfresco</a> (<a href="http://forums.alfresco.com/en/viewtopic.php?f=10&amp;t=21366" rel="nofollow">with a forum talk here</a>), <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.ow2.bonita/bonita-server/5.4.2/org/ow2/bonita/services/impl/RetryInterceptor.java#RetryInterceptor" rel="nofollow">Bonita</a> and <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.ow2.orchestra/orchestra-core/4.7.1/org/ow2/orchestra/services/commands/RetryInterceptor.java" rel="nofollow">Orchestra</a> have some methods to rerun such transactions too, and they are catching much more Exceptions, like <code>StaleObjectStateException</code> for instance (the cause of my <code>OptimisticLockException</code>).</p>
  
  <p>My 2nd question follows : for the <code>StaleObjectStateException</code> (<em>"Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)"</em>), normaly you can't just rerun the transaction, as it's a problem of synchronisation with the database and <code>@Version</code> fields isn't it ? Why Alfresco for instance tries to rerun such Transactions caused by such Exceptions ?</p>
  
  <p>EDIT :
  For <code>LockAcquisitionException</code> caused by <code>SQLServerException</code>, I've looked at some some resources on the web, and even if I should double check my code, it seems that it can happend anyway ... here are the links :</p>
  
  <ul>
  <li><a href="http://blog.sqlauthority.com/2007/05/16/sql-server-fix-error-1205-transaction-process-id-was-deadlocked-on-resources-with-another-process-and-has-been-chosen-as-the-deadlock-victim-rerun-the-transaction" rel="nofollow">An article on the subject</a> (with a <a href="http://blog.sqlauthority.com/2007/05/16/sql-server-fix-error-1205-transaction-process-id-was-deadlocked-on-resources-with-another-process-and-has-been-chosen-as-the-deadlock-victim-rerun-the-transaction/#comment-127607" rel="nofollow">comment</a> which says it can happend by running out of resources also)</li>
  <li><a href="http://social.msdn.microsoft.com/Forums/en-US/sqlintegrationservices/thread/194f18b0-03b2-4e8f-8c67-5c92373c3efd/" rel="nofollow">Another article</a> with sublinks :
  <ul>
  <li><a href="http://support.microsoft.com/kb/832524/en-us" rel="nofollow">Microsoft talking about that on support.microsoft.com</a></li>
  <li><a href="http://www.developer.com/db/article.php/10920_3490086_2" rel="nofollow">A way to profile transactions</a></li>
  <li><a href="http://www.sql-server-performance.com/2006/deadlocks/" rel="nofollow">And some advice to reduce such problems</a></li>
  </ul></li>
  </ul>
  
  <p>Even Microsoft says <em>"Although deadlocks can be minimized, they cannot be completely avoided. That is why the front-end application should be designed to handle deadlocks."</em></p>