在 spring/hibernate 应用程序中,我每晚都会运行一些 cronjobs。其中一个应该在多个事务中完成它的工作,如下所示:
@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();
// ...
}
我的弹簧配置的一部分:
<!-- Transaction -->
<tx:annotation-driven mode="aspectj" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
这里的关键点是我不想有一个长期运行的事务。因此,首先我获取所有客户并为每个客户调用一个事务方法。(我希望发布的代码足以理解问题)
当然,我得到一个 LazyInitializationException,因为当围绕“getCustomer”的事务提交时,Spring 正在关闭会话。
我能想到的可能解决方案:
我可以使用 OpenSessionInViewInterceptor 但这是一个 Web 组件
我可以使用 session.merge(customer) 重新附加分离的对象
这是 Propagation.Nestedtransaction 的情况吗?嵌套事务的语义是什么?大多数数据库没有嵌套事务(postgresql有但我没用过,叫做两阶段提交
我可以重写方法以使用 customerId 并在第二个事务中再次加载客户
现在我有两个关于我的问题的问题:
您如何编写测试来重现上述错误?
我怎样才能轻松地围绕这个展开一个开放的会话,或者在多个事务中完成大量工作的最佳方式是什么?