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

Spring Boot中AbstractRoutingDataSource请求间数据源共享问题咨询

问题解答

为啥Spring Boot请求会共享ThreadLocal的值?

Spring Boot默认用Tomcat作为Web容器,而Tomcat是用线程池来处理请求的:

  • 一个请求处理完后,线程不会被销毁,而是放回线程池等待下一个请求复用。
  • ThreadLocal的变量是绑定在线程实例上的,不是绑定在请求上。如果上一个请求没清理ThreadLocal里的值,下一个请求复用这个线程时,就能直接读到之前遗留的数据源标识(比如你遇到的ABC)。
  • 你碰到的1/5概率,本质是刚好命中了没清理ThreadLocal的复用线程的概率,这个概率和线程池大小、请求并发量直接相关。

必须清理ThreadLocal的原因

  1. 避免请求数据污染:后续请求会错误使用前一个请求的数据源,导致查询/操作错数据库,引发业务逻辑混乱。
  2. 防止内存泄漏:线程池里的线程是长期存活的,如果ThreadLocal绑定的对象一直没被清理,这些对象会一直被线程引用,无法被GC回收,积累多了会导致内存溢出。
  3. 符合线程复用的规范:线程池中的线程是共享资源,必须保证线程在处理新请求前是“干净状态”,不能遗留上一次请求的任何状态数据。

修复代码建议

一定要用try-finally包裹ThreadLocal的设置和清理逻辑,确保无论业务代码是否抛出异常,都会清理ThreadLocal:

public class ClientService {

    private ClientDao clientDao;

    @Autowired
    private ClientDatabaseContextHolder clientDatabaseContextHolder;

    public String getClientName(ClientDatabase clientDb) {
        try {
            clientDatabaseContextHolder.set(clientDb); // 设置当前请求的数据源标识
            return this.clientDao.getClientName();
        } finally {
            clientDatabaseContextHolder.clear(); // 强制清理,保证线程状态干净
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:06:02