Как настроить RetryAdvice и ExceptionTranslation для взаимоблокировок с помощью NHibernate и Spring - PullRequest
5 голосов
/ 16 марта 2010

Я использую Spring.net 1.2 с NHibernate 2.0.1.
В рамках моего проекта я сталкиваюсь с некоторыми проблемами тупиковой ситуации и, помимо настройки базы данных, чтобы свести к минимуму случаи, когда я хотел бы реализовать Springs RetryAdvice для решения этой проблемы.
Я не могу найти ни одного рабочего примера, как настроить это. Ссылка, кажется, ясно о том, как его использовать, но почему-то я не могу заставить его работать.

<!--Used to translate NHibernate exception to Spring.DataAccessExceptions-->    
<object type="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor, Spring.Data"/>

<!--ExceptionHandler performing Retry on Deadlocks-->
<object name="ExceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
  <property name="retryExpression" value="on exception name DeadLockLoserException retry 3x rate (1*#n + 0.5)"/>
</object>

Я добавил атрибут [Repository] в мои DAO, чтобы включить ExceptionTranslation, и попытался добавить RetryAdvice в используемый мной TransactionProxyFactoryObject, но он не будет работать. Я не понимаю, где поставить этот совет. Должен ли я объявить PointCut, чтобы добавить его, или как я могу заставить его работать как положено.

Спасибо заранее - любая помощь приветствуется.

1 Ответ

9 голосов
/ 04 мая 2010

После полутора месяцев ожидания того, как кто-то решит мою проблему, я наконец нашел время, чтобы разработать решение для этого самостоятельно. На самом деле это было не так сложно, как мне казалось. Может быть, поэтому я не смог найти хорошего примера. Итак, начнем: следующий тест покажет использование:

Конфигурация: (SessionFactory и TransactionManager и т. Д. Для краткости опущены)

  <!-- Retries the Tx after DeadlockExceptions -->
  <object name="ExceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
    <property name="retryExpression" value="on exception name DeadlockLoserDataAccessException retry 3x delay 1s"/>
  </object>

  <!--A Transaction-Configuration for our DAO-MOCK-->  
  <object id="TxProxyConfigurationTemplate" abstract="true" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
    <property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>

    <property name="TransactionAttributes">
      <name-values>
        <add key="ThrowDeadLock*" value="PROPAGATION_REQUIRED"/>
      </name-values>
    </property>
  </object>

  <object id="MockDaoTxPFO" parent="TxProxyConfigurationTemplate">
    <property name="Target" ref="MockDao"/>
  </object>

  <!--The ProxyFactoryObject based on the DAO-Mock interface-->
  <object id="MockDao" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop" >
    <property name="proxyInterfaces" value="RetryAdvice.IDaoMock"/>
    <property name="target" ref="MockDaoImpl"/>
    <property name="interceptorNames">
      <list>
        <value>ExceptionHandlingAdvice</value>
      </list>
    </property>
  </object>

  <!--Mocked DAO Implementation -->
  <object id="MockDaoImpl" type="RetryAdvice.DaoMock, RetryAdvice">
    <constructor-arg name="maxExceptionCount" value="2" />
  </object>

Mocked Dao: этот DAO дважды генерирует исключения DeadLockLooserException, а затем передает.

public interface IDaoMock
{
    void ThrowDeadLock();
    int MethodCallCount { get; }
}

[Repository]
public class DaoMock : IDaoMock
{
    private int maxExceptionCount;
    public int MethodCallCount { get; private set; }

    public DaoMock(int maxExceptionCount)
    {
        this.maxExceptionCount = maxExceptionCount;
    }

    public void ThrowDeadLock()
    {
        MethodCallCount++;
        if (MethodCallCount <= maxExceptionCount)
        {
            throw new DeadlockLoserDataAccessException("FAKE", new HibernateException("This is a fake Exception.", null));
        }
    }

Тест:

[Test]
public void RetryAdviceTest()
{
    IDaoMock mockDao = (IDaoMock)this.appContext.GetObject("MockDaoTxPFO");
    mockDao.ThrowDeadLock();
    Assert.That(mockDao.MethodCallCount, Is.EqualTo(3));
}

Любые намеки или замечания приветствуются.

...