Challenge ! Spring + Hibernate = double transaction ?
Salut @ tous !
Je suis confronté à un pb avec Hibernate, Spring et les transactions : "[save|createQuery] is not valid without active transaction". J'utilise une Datasource configurée avec Tomcat, et je veux utiliser AOP pour la gestion des transactions :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<!--[all my mappings]-->
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.connection.datasource=java:comp/env/jdbc/myapp
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.current_session_context_class=thread
hibernate.transaction.factory_class=org.springframework.orm.hibernate3.SpringTransactionFactory
hibernate.show_sql=true
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" isolation="READ_COMMITTED" rollback-for="com.myapp.framework.exception.ManagerException" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop :p ointcut id="pcManager1" expression="execution(public * com.myapp.framework.dao.manager..*(..))" />
<aop :p ointcut id="pcManager2" expression="execution(public * com.myapp.dao.manager..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pcManager1" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pcManager2" />
</aop:config> |
Tout semble OK dans les logs :
Code:
1 2 3 4 5 6 7
|
opened session at timestamp: 12306501743
DEBUG [org.hibernate.jdbc.ConnectionManager] (ConnectionManager.java:415) - opening JDBC connection
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:54) - begin
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:59) - current autocommit status: true
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:62) - disabling autocommit
DEBUG [org.hibernate.impl.SessionImpl] (SessionImpl.java:220) - opened session at timestamp: 12306501743 |
et lorsque j'appelle une sauvegarde sur la session, j'ai une exception :
Code:
1 2 3
|
session = ((SessionFactory) MyBeanFactoryFromSpring.getInstance().getBean(BeanConstants.SESSION_FACTORY)).getCurrentSession();
session.save(myObject); |
.. ce qui provoque ..
Code:
1 2 3 4
|
org.hibernate.HibernateException: save is not valid without active transaction
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:297)
... |
De plus, la transaction ouverte précédemment semble pourtant bien faire un rollback !!
Code:
1 2 3 4 5 6
|
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:152) - rollback
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:193) - re-enabling autocommit
DEBUG [org.hibernate.transaction.JDBCTransaction] (JDBCTransaction.java:163) - rolled back JDBC Connection
DEBUG [org.hibernate.jdbc.ConnectionManager] (ConnectionManager.java:296) - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
DEBUG [org.hibernate.jdbc.ConnectionManager] (ConnectionManager.java:435) - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)] |
Enfin, à noter que lorsque j'utilise la méthode "manuelle" (à savoir beginTransaction et commit), cela fonctionne !!! Je n'y comprends plus rien..
Quelqu'un a une idée sur cette "double transaction" ?
re: Challenge ! Spring + Hibernate = double transaction ?
Techniques alternatives
Dans certains projets, les techniques traditionnelles ne peuvent pas être implémentées facilement à cause d'un historique sans Spring et d'erreurs de programmation antérieures.
[modifier]Configuration hibernate.cfg.xml
Dans l'exemple de configuration précédente, le bean de SessionFactory remplace totalement le fichier de configuration hibernate.cfg.xml. Dans le cadre d'une intégration progressive de Spring, il peut être intéressant de brancher le SessionFactory sur un fichier hibernate.cfg.xml existant :
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="configLocation"> <value>hibernate.cfg.xml</value> </property> </bean>
Le problème de cette technique est que la gestion automatique des transactions par Spring ne fonctionne plus. Un contournement est de modifier le fichier de configuration d'Hibernate :
<hibernate-configuration>
<session-factory>
...
<property name="hibernate.current_session_context_class">
org.springframework.orm.hibernate3.SpringSessionContext
</property>
...
</session-factory>
</hibernate-configuration>
Un nouveau problème apparaît alors : Les sessions et transactions ne fonctionnent plus hors de Spring ! Ce qui est très gênant pour une intégration progressive.
Pour contourner ce nouveau problème, il faut initialiser la synchronisation entre Spring et les threads :
if (! TransactionSynchronizationManager.isSynchronizationActive())
TransactionSynchronizationManager.initSynchronization();
L'initialisation doit être faite une seule fois par thread, sous peine d'une exception de type java.lang.IllegalStateException, avec le message "Cannot activate transaction synchronization - already active". C'est pour éviter celà que je fais un test préalable.
Grâce à cette technique, les mêmes classes de DAO peuvent être utilisées par des services dans Spring, utilisant donc le TransactionManager de Spring, et par des services externes à Spring, manipulant directement des sessions et transactions via les classes d'Hibernate.
Attention : cette technique n'est généralement pas préconisée ; elle est utile dans une période de transition.
Récupérée de « http://www.jtips.info/index.php?titl...g-Transactions »
PS: j'ai trouvé ça sur http://www.jtips.info/index.php?titl...g-Transactions