You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Tomcat工作线程是否会复用Spring应用的InheritableThreadLocal数据?

多租户架构下Tomcat线程复用导致租户上下文串值问题

背景

  • 我们将Spring应用从单数据库服务所有客户架构改造为单客户单数据库架构,基于Hibernate提供的CurrentTenantIdentifierResolver、AbstractDataSourceBasedMultiTenantConnectionProviderImpl等接口实现多租户逻辑。
  • 每个HTTP请求完成认证后,在Spring过滤器中根据登录用户信息,将当前客户对应的数据库名称存入String类型的InheritableThreadLocal(命名为TenantContext),并在请求处理结束后将该值置为null。

问题现象

出现间歇性数据串库bug:客户B的业务数据被错误写入客户A的数据库。通过日志追踪发现,Tomcat工作线程http-nio-8080-exec-567先后处理了客户A和客户B的请求:

  • 处理客户A请求时,TenantContext中设置的租户标识(数据库名)为master;
  • 处理客户B请求时,该线程直接复用了前一个请求留下的master租户标识,关键日志如下:
[07:15:48.564] [http-nio-8080-exec-567] [70055303-3d0f-48c9-97b5-e7c3b54e9ddc] [] [] [c.s.w.d.t.CurrentTenantIdentifierResolverImpl:27] [DEBUG] - Tenant code is not null. Returning master
[07:15:48.564] [http-nio-8080-exec-567] [70055303-3d0f-48c9-97b5-e7c3b54e9ddc] [] [] [c.s.w.d.d.DynamicDataSourceBasedMultiTenantConnectionProvider:79] [DEBUG] - Selected master datasource. tenantCode master PoolName masterDataSource
[07:15:48.570] [http-nio-8080-exec-567] [70055303-3d0f-48c9-97b5-e7c3b54e9ddc] [] [] [c.s.w.c.CustomAuthenticationSuccessHandler:47] [INFO] - notification token deactivated while logging out for user 987654321
[07:15:48.570] [http-nio-8080-exec-567] [70055303-3d0f-48c9-97b5-e7c3b54e9ddc] [] [] [c.s.w.c.CustomAuthenticationSuccessHandler:52] [INFO] - targetUrl /
[07:15:48.572] [http-nio-8080-exec-567] [70055303-3d0f-48c9-97b5-e7c3b54e9ddc] [] [] [c.s.w.c.SecurityConfig$2:293] [INFO] - audit after request [ POST /some/other/api]
[07:16:00.767] [http-nio-8080-exec-567] [40591c10-5b5d-4882-a999-3abe5e28fc7b] [] [] [c.s.w.c.SecurityConfig$2:287] [INFO] - audit before request [ POST /some/api]
[07:16:00.771] [http-nio-8080-exec-567] [40591c10-5b5d-4882-a999-3abe5e28fc7b] [Some_user] [] [c.s.w.d.t.CurrentTenantIdentifierResolverImpl:27] [DEBUG] - Tenant code is not null. Returning master

最后两行日志对应客户B的请求,可见其直接复用了前一个请求遗留的master租户标识。

排查与临时修复

深入排查后发现两个核心问题:

  1. 部分请求处理完成后,TenantContext中的租户标识未被正确清空,具体触发原因暂未明确;
  2. 过滤器中存在如下逻辑:
if (TenantContext.isNotNull()){ return TenantContext}
/* Set the TenantContext value from the authenticated user in the next steps */

移除这段代码后,串库问题彻底消失。

疑问

按理论认知,不同请求属于独立的线程上下文,ThreadLocal值不会跨请求复用,但实际问题确实通过移除上述代码解决了,想明确:Apache Tomcat的工作线程(如http-nio-8080-exec-567)是否会在未清空InheritableThreadLocal的情况下,将前一个请求的租户标识复用给下一个请求?

内容的提问来源于stack exchange,提问作者vvs14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 21:12:50