In a spring/hibernate application I have some cronjobs running every night. One of them should do its work in multiple transactions like this:
@Scheduled(cron = "...")
public void cron ( )
{
batchJob();
}
@Transactional(propagation = Propagation.NEVER)
public void batchJob ( )
{
List<Customer> customers = getCustomers();
for (Customer customer : customers
{
doSomething(customer);
}
}
@Transactional(readOnly = true)
protected List<Customer> getCustomers ( )
{
return customerRepository.getCustomers();
}
@Transactional
protected void doSomething (Customer customer )
{
// LazyInitializationException
customer.getAddress();
// ...
}
parts of my spring config:
<!-- Transaction -->
<tx:annotation-driven mode="aspectj" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
The key point here is that I don't want to have one long running transaction. So first I get all customers and call a transactional method for each customer. ( I hope the code posted is enough to understand the problem)
Of course I get a LazyInitializationException because Spring is closing the session when the Transaction around 'getCustomer' is committed.
possible solutions i can think of:
I can use an OpenSessionInViewInterceptor but this is a web component
I can reattach the detached object with session.merge(customer)
Is this a case for Propagation.Nestedtransaction? What are the semantics of nested transaction? Most databases don't have nested transaction (postgresql does but I have never used it, it is called two phase commit
I can rewrite the method to consume customerId and load the customer again inside the second transaction
Now I have two questions concerning my problem:
How can you write a test to reproduce the bug above?
How can I easily span an open session around this or what is the best way to do a bunch of work in multiple transactions?
protected void doSomething (Customer customer )
instead ofprotected void do (Customer customer )
? – Oleksandr Bondarenkoaspectj
mode is enabled? Since if it would you didn't getLazyInitializationException
. – Oleksandr BondarenkobatchJob()
hasPropagation.NEVER
, therefore methods called from it would have their own sessions. – axtavt... self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.
– Oleksandr Bondarenko