J'ai deux bases de données, avec deux ensembles de configurations de ressort: Le niveau inférieur est CORE
db, le niveau supérieur est APP
db.Spring pour ouvrir automatiquement un autre gestionnaire de transactions?
Chaque db a son persistenceUnit, EntityManagerFactory, transactionManager, avec le nom db joint, tels que "entityManagerFactoryApp", "transactionManagerCore" ...
Maintenant, j'ai une classe de service, l'emballage des OTI dans l'APP , et certains dans CORE. Mais je trouve que je ne peux pas engager les OTI de base dans mon test:
Voici ma classe de service:
@Inject private AppDao appDao;
@Inject private CoreDao coreDao;
@Override
@Transactional
public void someMethod(foo bar)
{
appDao.save(...); //success
coreDao.save(...); //failed !
}
Et c'est ma classe de test:
@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(...);
}
}
Je sais que la raison pour laquelle je ne peux pas commettre Le DAO de CORE est dû au fait que la @TransactionConfiguration de la classe de test est "transactionManagerApp
" et non "transactionManagerCore
". Ainsi, toutes les actions CREATE/UPDATE/DELETE dans les DAO de CORE ne seront pas validées. Mais je ne peux pas activer deux txManagers simultanément (y at-il un moyen?).
Alors, je modifie ma classe de service:
@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();
}
Oui, ça marche! Mais ce n'est pas ce que je veux! Parce qu'il introduit beaucoup de codes redondants (session, tx, commit ...).
Et ... il y a une autre façon, pour supprimer la session/EntityManagerFactoryUtils de service, et les déplacer dans la classe de test:
@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();
}
}
cela fonctionne aussi, mais il est le même trop laid!
Maintenant, ma question est, est-il possible pour le printemps pour ouvrir automatiquement le transactionManager lié (s) et début/fin tx? PS: J'ai remarqué ceci: 10.5.6.2 Multiple Transaction Managers with @Transactional, mais il semble ne pas remplir mon exigence: pour ouvrir un autre txManager dans ONE
méthode.
environnements: printemps-3.0.5, mise en veille prolongée-3.6.0, JPA2
- mis à jour -
Merci @Bozho pour me dire d'appeler une nouvelle @Transactional (valeur = "txMgrName") méthode, j'ai essayé, mais toujours pas:
Voici mon code de service:
@Override
@Transactional
public void someMethod(foo bar)
{
appDao.save(...); //success
someCoreMethod();
}
@Transactional(value="transactionManagerCore" , propagation=Propagation.REQUIRES_NEW)
private void someCoreMethod(...)
{
coreDao.save(...); //failed
}
dans core.xml:
<bean id="transactionManagerCore" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryCore" />
<qualifier value="transactionManagerCore"/>
</bean>
Il reste a échoué, le coreDao sauve toujours rien. Je pense que c'est peut-être parce que la méthode est privée, et non interceptée par Spring. J'extrait la méthode dans le niveau d'interface/de mise en œuvre:
Service (interface)
public void someMethod(foo bar)
public void someCoreMethod(...)
ServiceImpl (class) : unchanged
Mais toujours pas! En fait, j'ai trouvé que le ressort ignore l'annotation @Transactional dans someCoreMethod().
Je peux même annoter @Transactional (valeur = "non-existence txManager nom") avec un MAUVAIS txManager, et le printemps ne signale aucune erreur (et rien engage)!
Ai-je raté quelque chose?
* Il est une autre histoire que ce soit une bonne pratique * une histoire tout à fait différente, oui ... :-) bonne réponse btw –
Merci, j'ai essayé, mais toujours échoué. Pourriez-vous jeter un coup d'œil? (J'ai mis à jour mon contenu) – smallufo
@smallufo - désolé, oublié de mentionner - placez la méthode dans une nouvelle classe. – Bozho