手动提交带有 @Transactional 属性的操作

3

我使用spring+hibernate模板处理实体。有大量实体需要一次性加载,因此我从hibernate模板中检索出一个迭代器。

每个实体都应该作为单个工作单元进行处理。我试图将实体处理放在单独的事务中(传播=REQUIRED_NEW)。然而,我最终遇到了一个异常,指出代理绑定了两个会话。这是由于用于迭代器惰性加载的挂起事务所致。我正在使用同一bean进行惰性加载和实体处理。(也许它应该重构成两个单独的dao:一个用于惰性加载,另一个用于处理?)

然后我尝试使用单个事务,在处理每个实体后提交。在这里更好,实体处理期间没有异常,但在处理完成并返回方法后,从spring事务管理代码抛出异常。

@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是另一个bean中带有@Transactional注解的方法,因此所有实体都有一个事务。我检查了哪个事务引起了异常: 它是从hibernateSession.beginTransaction()返回的第一个事务,所以它在事务管理器中没有更新。

有几个问题:

是否可以在不重构dao的情况下避免会话绑定异常? 这不是相关的问题,因为问题出在Session和Hibernate上,而不是dao。

是否可能在事务管理器中更新事务? 已解决

是否可能在processManyManyEntities上没有@Transactional注解的情况下使用相同的事务(对于anotherBean.processSingleEntity(entity);)?

2个回答

1

我更倾向于在“processManyManyEntities()”上删除@Transactional注释,并且急切地从“findEntitesForProcessing”加载所有数据。

如果您希望每个数据实体在“processSingleEntity”中进行事务处理,则“processSingleEntity”上的@Transactional是可以的。您不必在“processManyManyEntities()”上注释@Transactional。但是,在惰性加载的情况下,急切加载是防止源数据在另一个会话中加载(例如在“processSingleEntity”中)的必要手段。

由于每个数据实体的事务,源数据加载的事务边界并不是您事务的情况。不要让“惰性加载”复杂化您修改数据意图的事务。


我无法避免懒加载,因为我有成千上万的实体。 - michael nesterenko
也许你可以尝试一次处理几个条目,并使用急加载。但如果你能更详细地描述“findEntitesForProcessing”,会更清楚一些。在“processSingleEntity”内部,将处理多少数据? - Mike Lue
幸运的是,我们有一种方式可以在事务管理器中更新事务。我已经添加了一个详细的答案。预先加载多个实体的想法很好!如果没有找到任何东西,我会使用它的! :) - michael nesterenko

1

在事务管理器中更新事务是可能的。您需要做的就是从TransactionSynchronizationManager.getResource(sessionFactory)获取SessionHolder实例,并将事务设置为当前会话持有者。这样可以在必要时提交事务,并允许Spring事务管理器在方法返回后提交事务。


有没有可能提供一个例子?解决方案不是很清晰,但似乎很有趣。 - Tobia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接