SpringTys @Transactional @Scheduled не передано в БД? - PullRequest
8 голосов
/ 26 марта 2011

Я впервые пробую @Scheduled в Spring3, но обнаружил, что не могу зафиксировать в БД. Это мой код:

@Service
public class ServiceImpl implements Service , Serializable
{
  @Inject 
  private Dao dao;

  @Override
  @Scheduled(cron="0 0 * * * ?") 
  @Transactional(rollbackFor=Exception.class)
  public void hourly()
  {
    // get xxx from dao , modify it
    dao.update(xxx);
  }
}

Я думаю, что это должно работать, я вижу, что он запускается ежечасно и загружает xxx из БД, но данные не передаются в БД.

Там было tx:annotation-driven в весеннем xml:

<bean id="entityManagerFactoryApp" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="myapp"/>
</bean>
<bean id="transactionManagerApp" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactoryApp" />
</bean>

<tx:annotation-driven transaction-manager="transactionManagerApp" />

Может кто-нибудь сказать мне, что я здесь пропустил?

У меня есть одно ' грязное ' решение:

@Service
public class ServiceImpl implements Service , Serializable
{
  @Inject 
  private Dao dao;

  @Inject
  @Qualifier("transactionManagerApp")
  private PlatformTransactionManager txMgrApp;

  @Override
  @Scheduled(cron="0 0 * * * ?")
  @Transactional(rollbackFor=Exception.class)
  public void hourly()
  {
    final TransactionTemplate txTemplateApp = new TransactionTemplate(txMgrApp);
    txTemplateApp.execute(new TransactionCallbackWithoutResult()
    {
      @Override
      protected void doInTransactionWithoutResult(TransactionStatus status)
      {
        //get xxx from dao
        dao.update(xxx);
      }
    });
  }
}

Здесь отлично работает , но он настолько избыточен, что затрудняет чтение кода. Интересно, почему TransactionManager не вставляется (и не открывается) в предыдущих фрагментах кода?

Большое спасибо!

Ответы [ 3 ]

17 голосов
/ 18 октября 2012

Вы, вероятно, уже поняли это или пошли дальше (я надеюсь на это), но в интересах других:

Аннотация @Transactional говорит Spring обернуть ваш оригинальный компонент ServiceImpl динамическим проксиэто также реализует 'Service' (по умолчанию Spring проксирует интерфейс, а не реализацию).Этот прокси будет прозрачно обрабатывать создание и принятие / откат транзакции, когда вы вызываете hourly() на прокси .Однако, если вы вызываете hourly() непосредственно в своей реализации (что и происходит выше), прокси-сервер будет обойден, и транзакция не будет выполнена.

http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/

Решениелибо

  1. Программно разграничить транзакцию, как вы делаете это в «грязном» решении (в данном случае вам не нужны аннотации).
  2. Убедитесь, что ваш @ScheduledМетод обращается к dao.update(xxx); через интерфейс Сервиса, а не непосредственно к вашей реализации (таким образом, проходя через прокси).По сути, вам нужно перенести метод @Scheduled на другой компонент.

Надеюсь, это достаточно ясно!

0 голосов
/ 26 апреля 2015

У меня была такая же проблема, и, потратив на это время, я понял, что получил исключение после вызова dao.update () в каком-то не связанном коде, который не проверял нулевое значение - поэтому он просто прервал транзакцию.Не было никакой печати stackTrace, потому что она была хорошо обработана к весне (некоторый блок catch).Я потратил некоторое время на это.Так что - просто убедитесь, что ваш метод транзакции завершается до конца.Надеюсь, это кому-нибудь поможет.

Йоси Лев

0 голосов
/ 26 марта 2011

Когда вы используете поддержку, основанную на аннотациях, она работает только с классами, созданными в этом контексте. Держу пари, что ServiceImpl не создается в том же контексте, что и менеджер транзакций (напрямую или путем сканирования аннотаций).

...