Spring для автоматического открытия другого транзакцииManager? - PullRequest
1 голос
/ 12 декабря 2010

У меня есть две базы данных с двумя наборами конфигураций пружин: нижний уровень - CORE дБ, верхний уровень - APP дБ.

У каждого БД есть свой persistenceUnit, entityManagerFactory, TransactionsManager, с добавленным именем БД, например, "entityManagerFactoryApp", "TransactionsManagerCore" ...

Теперь у меня есть класс Service, заключающий в себе некоторыеDAO в APP, а некоторые в CORE.Но я обнаружил, что не могу зафиксировать DAO в CORE в моем тесте:

Вот мой класс обслуживания:

  @Inject private AppDao  appDao;
  @Inject private CoreDao coreDao;

  @Override
  @Transactional
  public void someMethod(foo bar)
  {
    appDao.save(...); //success    
    coreDao.save(...); //failed !
  }

И это мой тестовый класс:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:app.xml"})
@TransactionConfiguration(transactionManager="transactionManagerApp" , defaultRollback=false)
public class ServiceTest
{
  @Inject private Service service;

  @Test
  @Transactional
  public void testSomeMethod()
  {
    service.someMethod(...);
  }
}

Iзнаю причину, по которой я не могу зафиксировать DAO в CORE, потому что @TransactionConfiguration тестового класса имеет значение "transactionManagerApp", а не "transactionManagerCore".Таким образом, любые действия CREATE / UPDATE / DELETE в DAO CORE не будут совершены.Но я не могу включить два txManager одновременно (есть ли способ?) .

Итак, я изменяю свой класс обслуживания:

@Inject
  @Qualifier("entityManagerFactoryCore")
  private EntityManagerFactory emfCore;

  @Override
  @Transactional
  public void someMethod(foo bar)
  {
    appDao.save(...); //success    

    Session session = (Session) EntityManagerFactoryUtils.getTransactionalEntityManager(emfCore).getDelegate();
    Transaction tx = session.beginTransaction();
    coreDao.save(...); //success
    tx.commit();
  }

Да, это работает!Но это НЕ то, что я хочу!Потому что он вводит много избыточных кодов (session, tx, commit ...).

И ... есть еще один способ удалить session / EntityManagerFactoryUtils из Service и переместить их в тестовый класс:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:app.xml"})
@TransactionConfiguration(transactionManager="transactionManagerApp" , defaultRollback=false)
public class ServiceTest
{
  @Inject private Service service;

  @Inject
  @Qualifier("entityManagerFactoryCore")
  private EntityManagerFactory emfCore;

  @Test
  @Transactional
  public void testSomeMethod()
  {
    Session session = (Session) EntityManagerFactoryUtils.getTransactionalEntityManager(emfCore).getDelegate();
    Transaction tx = session.beginTransaction();
    service.someMethod(...);
    tx.commit();
  }
}

это тоже работает, но тоже ужасно!

Теперь мой вопрос, есть ли у Spring способ автоматически открыть связанные транзакции и менеджер транзакций иначало / конец tx?

PS: я заметил это: 10.5.6.2 Менеджеры множественных транзакций с @ Transactional , но это, кажется, не выполняет мое требование: открыть другой txManager в методе ONE.

Среды: spring-3.0.5, hibernate-3.6.0, JPA2

- обновлено -

Спасибо @Bozho за сообщение о вызове нового @Транзакционный (value = "txMgrName") метод, который я пробовал, но все равно не удался:

Вот мой код службы:

  @Override
  @Transactional
  public void someMethod(foo bar)
  {
    appDao.save(...); //success   
    someCoreMethod(); 
  }

  @Transactional(value="transactionManagerCore" , propagation=Propagation.REQUIRES_NEW)
  private void someCoreMethod(...)
  {
    coreDao.save(...); //failed
  }

в core.xml:

  <bean id="transactionManagerCore" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactoryCore" />
    <qualifier value="transactionManagerCore"/>
  </bean>

Всё равно не получилось, coreDao всё равно ничего не экономит.Я думаю, может быть, это потому, что метод является частным и не перехвачен Spring.Поэтому я извлекаю метод на уровень интерфейса / реализации:

Service (interface)
  public void someMethod(foo bar)
  public void someCoreMethod(...)

ServiceImpl (class) : unchanged

Но все равно не получилось!Фактически, я обнаружил, что spring пропускает аннотацию @Transactional в someCoreMethod ().

Я даже могу аннотировать @Transactional (value = " non-creation-txManager-name") с НЕПРАВИЛЬНЫМ txManager, и Spring не сообщает об ошибке (и ничего не фиксирует)!

Я что-то пропустил?

1 Ответ

2 голосов
/ 12 декабря 2010

Вы можете сделать это через xml - <aop:config> (в связанных документах есть пример). Он создаст два прокси вокруг объекта, и, следовательно, 2 транзакции будут зафиксированы. Другое дело, является ли это лучшей практикой.

Другой вариант - вызвать новый метод (в новом классе) с

@Transactional(propagation=REQUIRES_NEW, "anotherTransactionManager")
...