返回
Mybatis Plus 多租户:改造路上踩坑指南
后端
2023-10-02 01:57:37
前言
最近公司的老项目要改造多租户,于是我进入了大坑,本文写点遇到的坑以及解决方案,每次遇到问题在网上搜了好久,记录下来,防止以后忘掉。
方案
网上有很多方案,我们采用了在数据源上做文章。数据源通过一个叫做Druid的数据源池进行管理,具体方案是让Druid根据不同的租户自动切换数据源。
坑一:数据源无法自动切换
Druid的数据源切换是通过一个叫做ShardingFilter的过滤器来实现的,ShardingFilter根据请求中的某个字段来决定使用哪个数据源。我们在请求头中添加了一个叫做tenantId的字段,值是租户的ID。
public class TenantIdFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String tenantId = request.getHeader("tenantId");
if (tenantId != null) {
DruidDataSourceHolder.setTenantId(tenantId);
}
filterChain.doFilter(request, response);
}
}
然后在Druid的配置中添加ShardingFilter,并将ShardingFilter的strategy设置为tenantId。
<filter>
<name>shardingFilter</name>
<class>com.alibaba.druid.filter.FilterAdapter</class>
<init-param>
<name>strategy</name>
<value>tenantId</value>
</init-param>
</filter>
但是在测试的时候发现,数据源并没有自动切换。排查问题发现,原来是Druid的配置中没有启用ShardingFilter。
<property name="filters" value="shardingFilter"/>
坑二:数据源切换后,事务失效
在数据源切换后,事务失效了。这是因为Druid的数据源池是独立的,每个数据源都有自己的事务管理器。所以,当数据源切换后,就需要重新创建一个事务管理器。
@Transactional(propagation = Propagation.REQUIRED)
public void saveUser(User user) {
if (user.getTenantId() != null) {
DruidDataSourceHolder.setTenantId(user.getTenantId());
}
userDao.save(user);
}
坑三:数据源切换后,Mybatis Plus的插件失效
在数据源切换后,Mybatis Plus的插件失效了。这是因为Mybatis Plus的插件是针对特定的数据源写的。当数据源切换后,Mybatis Plus的插件就无法找到对应的