有个项目用的 Spring Data Jpa ,里面需要多数据源来做分库,正常流程是拦截器拿出用户信息,然后把分库信息设置到 ThreadLocal 里,后面使用就没问题了。但最近遇到个问题,在 Service 层重新分库信息居然没用,依然会使用首次获取到的数据库连接。
项目里其实有类似的用发,同一个线程重新设置了分库信息也依然可以正确选中,直接使用 JdbcTemplate 查询也没问题,So,到底什么问题呢?
还是对这套东西不熟悉,OpenEntityManagerInViewInterceptor 已经将 Hibernate Session 绑定到线程里了,怎么选都在这个事务里,Spring Boot 在启动的时候会给一个关于 spring.jpa.open-in-view 配置的警告,可以把这个功能关掉。
解决方法
- 关掉 spring.jpa.open-in-view 配置,但会影响懒加载功能。
- 比较粗暴,在一个新线程里执行,比如 Spring 的 @Async。
- 参考这里的方法,解绑然后重新绑定 EntityManager。
这个问题其实搞了几天,对 Spring Data Jpa 不熟,不知道 Spring 有这个东西,就想着在哪里保存了数据库连接信息,怎么把它解绑掉,自己实现了上面的方法3,后面再搜搜资料发现这是一个还算普遍的问题,前面搜索的关键信息不对。还有就是要注意 Spring 启动时候的日志,查查那些警告是什么意思。