Active Spring transaction synchronization or active JTA
During Spring development I got this exception, but there was almost no reference to what caused it. So after a lot of searching I found out the cause and thought I'd blog it for others struggling with the same problem.
java.lang.IllegalStateException: Active Spring transaction synchronization or active JTA transaction with specified [javax.transaction.TransactionManager] required at org.springframework.jdbc.support.lob.LobCreatorUtils.registerTransactionSynchronization(LobCreatorUtils.java:79) at org.springframework.orm.hibernate3.support.AbstractLobType.nullSafeSet(AbstractLobType.java:185) at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:146) at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:1997) at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:1974) at org.hibernate.persister.entity.AbstractEntityPersister$3.bindValues(AbstractEntityPersister.java:2152) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:32) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70) at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507) at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499) at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495) at org.springframework.orm.hibernate3.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:696) at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:373) at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:693) at uk.co.bigsoft.Manager.thumbs.ClipThumbnailManagerDaoHibernate.setClipThumbnail(ClipThumbnailManagerDaoHibernate.java:66) at uk.co.bigsoft.Manager.thumbs.ClipThumbnailManager.setClipThumbnail(ClipThumbnailManager.java:25) at uk.co.bigsoft.Manager.corba.ThumbnailReader.newThumbnail(ThumbnailReader.java:106) at uk.co.bigsoft.corba_2_3.ThumbnailListenerPOATie.newThumbnail(ThumbnailListenerPOATie.java:53) at uk.co.bigsoft.corba_2_3.ThumbnailListenerPOA._invoke(ThumbnailListenerPOA.java:50) at org.jacorb.poa.RequestProcessor.invokeOperation(RequestProcessor.java:299) at org.jacorb.poa.RequestProcessor.process(RequestProcessor.java:602) at org.jacorb.poa.RequestProcessor.run(RequestProcessor.java:745)
In order to add large binary objects to a hibernate persistent store (database), the action must be part of a transaction.
In the springframework you must have several beans set up. The first is a datasource bean. This describes how to talk to the database; what language to use, and how to access it.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myDb"/>
<property name="username" value="myUsername"/>
<property name="password" value="myPassword"/>
</bean>
The default behaviour of the DriverManagerDataSource is to use database transactions if possible. However you need a transaction manager inside the spring application to manage the transaction as a whole; i.e. there may be more transactional units other than a database transaction that need to be tied together, such as a Java Message Queue Transaction. It is this overall Transaction manager that controls whether a particular transaction is committed or rolled back.
Spring provides a factory for creating (or reusing already existing) transaction objects depending on the code we are currently running through.
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
The transaction manager organises the rules of how one transaction interacts with another, for example we don't want to fail a larger transaction because a smaller unit of work fails - we would want to retry the smaller transaction several times before failing the larger transaction. The transaction manager manages this.
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<ref local="jotm" />
</property>
</bean>
We would like to use annotations in our code so we will need to tell the xml engine how to understand <tx : ??> namespace tags.
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
">
Next we set the transaction manager to use when we use transaction annotations in our code.
<tx:annotation-driven transaction-manager="transactionManager"/>
Large binary objects need to run inside a transaction because they may have several stages that need to be completed before we can continue. If one of the stages fails, we need to be sure that the system will be able to clean up after us. Spring enforces this as a requirement.
We need a bean to manage the handling of a Large Object (LOB). Spring's job is to abstract away the complexities of handling 3rd party APIs. Different databases handle LOBs in different ways so we need a LOB handler to take care of them for us:
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
We are going to use Hibernate as our object persistence store, so we need a session factory to get our Hibernate sessions. The Session Factory needs to know how to talk to the database and how to handle LOBs. We'll use a bean for that.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="lobHandler" ref="defaultLobHandler"/>
<!-- other properties -->
</bean>
Unfortunately I wrote this ages ago but never finished it and never published it. I don't work in this area any more and don't have the will power to get back into Spring. So I publish it uncompleted with just a reference to what I was going to put in it. Maybe the first part will give help to some one looking for the meaning of the exception.
TODO: show an hbm mapping for the database show a pojo using input stream show doa using @Transaction without @Transactional you get the error.
No feedback yet
Form is loading...