Использование распространения Spring @Transactional в JTA

Я пытаюсь реализовать стратегию клиентской оркестровки (ibm -client-orchestration) благодаря нашей системной архитектуре. Мы используем уровень интеграции, который фактически управляет некоторыми веб-сервисами. Вызов веб-сервисов выполняется за одну единицу работы и делегируется бизнес-уровню, который использует среду Spring. Примером может быть что-то вроде этого:

UserTransaction ut = getUserTransaction()
ut.begin();
// insert data, will be delegated to some jpa repository
service1.saveData(data)
// find data inserted above
service2.findData(data)
ut.commit();

В упомянутой ссылке автор предлагает использовать распространение ОБЯЗАТЕЛЬНО при сохранении и распространение ПОДДЕРЖИВАЕТ при поиске, что попытается найти данные в журнале транзакций. Почему-то я не знаю, что не могу найти вставленные данные на шаге поиска, учитывая описанный выше сценарий. Вот некоторая полезная информация, которая может помочь:

  1. мы используем Websphere 8.5. Наш источник данных поступает из Websphere, настроен как источник данных XA и берется из JNDI.
  2. Менеджер транзакций платформы из Spring настроен как JtaTransactionManager
  3. Entity Manger Factory берется из LocalContainerEntityManagerFactoryBean и использует Hibernate JPA Vendor со следующими свойствами:

    jpaProperties.setProperty("hibernate.hbm2ddl.auto", environment.getRequiredProperty("entitymanagerfactory.hibernate.hbm2ddl.production")); jpaProperties.setProperty("hibernate.connection.autocommit", "false"); jpaProperties.setProperty("hibernate.transaction.jta.platform", "org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform"); jpaProperties.setProperty("hibernate.transaction.manager_lookup_class", "org.hibernate.transaction.WebSphereExtendedJTATransactionLookup");

  4. Я не настраивал провайдера JPA в Websphere, поэтому он должен быть реализацией по умолчанию.

Я упоминаю, что если я использую на уровне делегирования DAO метод saveAndFlush() из репозитория jpa, я могу найти его, но я бы предпочел не использовать его и использовать распространение транзакции.

Определение bean-компонента transactionManager:

    @Bean
public PlatformTransactionManager transactionManager() {
    JtaTransactionManager txManager = new JtaTransactionManager();
    txManager.afterPropertiesSet();
    return txManager;
}
    @Bean
public EntityManagerFactory entityManagerFactory() {
    // hibernate vendor
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setDatabase(databaseType());
    vendorAdapter.setGenerateDdl(true);

    // compose entityManager

    LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setJpaVendorAdapter(vendorAdapter);
    factoryBean.setDataSource(datasource());
    factoryBean.setJtaDataSource(datasource());
    // scan packages
    factoryBean.setPackagesToScan(environment.getRequiredProperty("entitymanager.scan.packages"));

    // JPA properties
    factoryBean.setJpaProperties(getEntityManagerFactoryJpaProperties());

    factoryBean.afterPropertiesSet();

    return factoryBean.getObject();
}

Любые предложения приветствуются. Спасибо.


person dumitru    schedule 04.02.2014    source источник
comment
Вы должны Spring обрабатывать жизненный цикл, вы не должны сами вызывать afterPropertiesSet, Spring сделает это за вас. То же самое с getObject(), вы должны просто вернуть FactoryBean, чтобы Spring мог правильно управлять им.   -  person M. Deinum    schedule 04.02.2014


Ответы (1)


Для начала вы должны использовать специфичный для веб-сайта JtaTransactionManager вместо общего. Я бы предложил использовать tag which detects which specific or generic one to use. So basically replace your definition of theJtaTransactionManager` со следующим:

<tx:jta-transaction-manager />

Затем ваш код не использует управление транзакциями spring, а простые транзакции JTA либо используют аннотации для управления транзакцией (@Transactional с <tx:annotation-driven />, либо используют введенный PlatformTransactionManager для запуска и фиксации транзакций.

TransactionStatus txStatus = getTransactionManager().getTransaction(null);
// insert data, will be delegated to some jpa repository
service1.saveData(data)
// find data inserted above
service2.findData(data)
getTransactionManager().commit(txStatus);

См. также справочное руководство для другого подхода и дополнительной информации.

В LocalContainerEntityManagerFactoryBean убедитесь, что вы внедрили свойство jtaDataSource вместо свойства dataSource, это вызовет некоторые дополнительные настройки.

@Bean
public FactoryBean<EntityManagerFactory> entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean();
    lcemfb.setJtaDataSource(dataSource());
    // .... Other properties
    return lcemfb;
}

Еще одно замечание о вашей конфигурации гибернации: свойства hibernate.connection.* бесполезны из-за внедрения источника данных, и вам не нужен hibernate.transaction.manager_lookup_class, поскольку он (или, по крайней мере, должен) уже покрываться настроенным JtaPlatform.

person M. Deinum    schedule 04.02.2014
comment
Я добавил комментарий о том, как он настраивает transactionManager и entityManagerFactory. Я бы сказал, что это то же самое, что вы упомянули. Я не уверен, есть ли у нас возможность получить диспетчер транзакций на нашем уровне интеграции, поскольку этот уровень не имеет ничего общего с Spring Framework. Спасибо за Ваш ответ. Я попробую, может быть, подход к поиску сервисов, чтобы получить диспетчер транзакций из весны. Если у вас есть другие идеи.. - person dumitru; 04.02.2014
comment
Нет, это не так .. ВЫ используете JtaTransactionManager, а не конкретную веб-сферу. Пространство имен определяет, какую версию использовать. Кроме того, ваш LocalContainerEntityManagerFactoryBean настроен неправильно, вы должны установить либо свойство dataSource, либо свойство jtaDataSource, а не оба. Что касается менеджера транзакций, у меня сложилось впечатление, что код управляется Spring, если не игнорировать эту часть. - person M. Deinum; 04.02.2014