3

我目前遇到了 Spring 事务管理器的意外行为:同一个事务被分配给多个线程。该场景是在 Tomcat 服务器中运行的 CXF Web 服务。服务本身是一个 Spring bean(单例)。当向服务器发送许多并行请求(在我的测试中我使用了 10 个)时,有时会发生两个请求(在不同的线程中运行)使用同一个事务。由于该逻辑设计为每个请求使用一个事务,因此此行为会导致应用程序的错误行为。

在我的服务类下面:

package ...clientsupport_v1;

import...

@WebService(targetNamespace = ...)
@Transactional(rollbackFor = MyException.class)
public class ClientSupportFacade extends AbstractServiceFacade implements ClientSupportService {

private static final Logger LOG = LoggerFactory.getLogger(ClientSupportFacade.class);

@Autowired
private HibernateTransactionManager transactionManager;

@Autowired
private ClientOrderImporter clientOrderImporter;

@Override
public Advice receiveClientPreAdvice(User user, PreAdvice preAdvice) throws MyException {
    LOG.debug("PreAdvice: " + preAdvice + ", Transaction: " + getTransactionId() + ", Thread: "
            + Thread.currentThread().getName());
...
    return advice;
}

private int getTransactionId() {
    return transactionManager.getSessionFactory().getCurrentSession().getTransaction().hashCode();
}

}

receiveClientPreAdvice 是作为服务操作公开的方法。

使用多个线程调用时,我得到以下日志行:

2013-10-29 13:59:25.135 DEBUG e.h.p.s.c.c.ClientSupportFacade.receiveClientPreAdvice:42 - PreAdvice: PreAdvice [barcode=90000000002161, ...], Transaction: 420660542, Thread: http-bio-8080-exec-9
2013-10-29 13:59:25.135 DEBUG e.h.p.s.c.c.ClientSupportFacade.receiveClientPreAdvice:42 - PreAdvice: PreAdvice [barcode=90000000002163, ...], Transaction: 420660542, Thread: http-bio-8080-exec-8

如您所见,已收到两个不同的对象,并且正在运行两个不同的线程。然而交易是一样的。

这怎么可能发生?而且——更重要的是——如何避免?

4

1 回答 1

0

来自HibernateTransactionManager javadoc:

将指定工厂的 Hibernate Session 绑定到线程,可能允许每个工厂有一个线程绑定 Session ...此事务管理器适用于使用单个 Hibernate SessionFactory 进行事务数据访问的应用程序,...

发布您的休眠配置可能会有所帮助,但从您的代码中,我可以看到您正在记录getTransaction().hashCode()为事务 ID,假设它们引用相同的事务对象,hashCode()而不需要为不同的对象返回不同的值。可以有 2 个不同的事务正在进行,它们都具有相同的哈希码值。

于 2014-01-30T06:09:06.767 回答