Reputation: 14439
I use spring+hibernate template to process entities. There is rather big amount of entities to be loaded all at once, so I retrieve an iterator from hibernate template.
Every entity should be processed as a single unit of work. I tried to put entity processing in a separate transaction (propagation = REQUIRED_NEW). However I ended with exception stating that proxy is bounded to two sessions. This is due to suspended transaction used for iterator lazy loading. I am using the same bean for lazy loading and for processing entities. (May be it should be refactored into two separate daos: one for lazy loading and one for processing?)
Then I tried to use single transaction that is committed after each entity is processed. Much better here, there are no exceptions during entity processing, but after processing is finished and method returns, exception is thrown from spring transaction managing code.
@Transactional
public void processManyManyEntities() {
org.hibernate.Sesstion hibernateSession = myDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
Iterator<Entity> entities = myDao.findEntitesForProcessing();
while (entities.hasNext()) {
Entity entity = entities.next();
hibernateSession.beginTransaction();
anotherBean.processSingleEntity(entity);
hibernateSession.getTransaction().commit();
}
}
processSingleEntity
is a method in another bean annotated with @Transactional
, so there is one transaction for all entities. I checked what transaction causes an exception: it is the very first transaction returned from hibernateSession.beginTransaction()
, so it just not updated in transaction manager.
There are several questions:
is it possible to avoid session bind exception without refactoring the dao? that is not relevant question as problem is with Session and hibernate not with dao
is it possible to update transaction in the transaction manager? solved
is it possible to use the same transaction (for anotherBean.processSingleEntity(entity);
) without @Transactional
annotation on processManyManyEntities
?
Upvotes: 3
Views: 3814
Reputation: 14439
That is possible to update transaction in transaction manager. All you need to do is get SessionHolder instance from TransactionSynchronizationManager.getResource(sessionFactory)
and set transaction in the session holder to the current. That makes possible to commit transaction whenever it is necessary and allows transaction to be committed by spring transaction manager after method return.
Upvotes: 1
Reputation: 839
I would prefer to remove the @Transactional annotation on "processManyManyEntities()", and, to eagerly load all data from "findEntitesForProcessing".
If your want each entity of data to be transactional in "processSingleEntity", the @Transactinoal on "processSingleEntity" is fine. You don't have to annotate the @Transactional on "processManyManyEntities()". But in case of lazy loading, eager loading is a necessary mean to prevent the source data from loading in another session, say, in "processSingleEntity".
Since the transaction for each entity of data, the transactional boundary in loading of source data is not the case of your transaction. Don't let the "lazy loading" to complicate your intent of transaction for modification of data.
Upvotes: 1