SpringBoot中Hibernate在WebSphere下的并发连接异常排查
问题场景
在WebSphere 9.0.5.11(Network Deployment)环境中搭配Hibernate Core 5.4.22开发时,遇到偶发异常:调用后端REST接口时,有时会抛出JpaSystemException,异常提示为:Detected concurrent management of connection resources...。但在本地Apache Tomcat环境中从未出现该问题。
核心疑问
- 该异常是否由WebSphere导致?
- 异常是否与WebSphere上通过JNDI配置的DB2 11.1.4.5 LUW数据源(而非JDBC直连)有关?
- REST API应用采用默认单例(Singleton)作用域,当两个前端用户调用同一接口并操作同一对象(如ID=1的Car对象)时,Hibernate加载该对象到持久化上下文后,两个用户是各自拥有独立的持久化上下文,还是共享同一个?
附加信息
异常堆栈信息
[请粘贴完整异常堆栈内容]
业务代码
CarService
// 粘贴CarService相关代码
LicensePlateService
// 粘贴LicensePlateService相关代码
DataSource配置代码
// 粘贴DataSource配置代码
问题解答
1. 异常是否由WebSphere导致?
是,但并非WebSphere的原生Bug,而是其连接池的严格并发校验机制与Hibernate的资源管理逻辑在多线程场景下产生冲突。WebSphere会对数据库连接的使用做严格的线程归属校验,当Hibernate出现连接资源跨线程操作(比如同一连接被多个线程同时持有并操作)时,就会触发该异常。而Tomcat的连接池校验逻辑相对宽松,不会触发此类校验,因此本地环境无问题。
2. 异常是否与JNDI配置的DB2数据源有关?
有关系。通过JNDI配置的WebSphere数据源由容器全权管理连接的生命周期(包括分配、回收、校验),而JDBC直连时连接由Hibernate直接管控。当Hibernate的事务管理节奏与WebSphere的连接池调度不同步时,就可能出现连接被多个线程并发操作的情况:比如WebSphere提前回收了连接,但Hibernate仍在尝试使用;或者连接被分配给新线程,但前一线程的数据库操作未完全结束。
3. 持久化上下文的作用域问题
两个用户各自拥有独立的持久化上下文。REST接口的每个请求由独立线程处理,默认情况下(以Spring生态为例),EntityManager是请求作用域的——即使你的Service是单例,每个请求会获取独立的EntityManager实例,对应独立的持久化上下文。因此两个用户的请求不会共享持久化上下文,各自加载的Car对象也是独立的实例(即使ID相同,在不同上下文属于不同对象)。
内容的提问来源于stack exchange,提问作者Ewe

