在 MyBatis 中实现动态 tenant 功能,通常是为了支持多租户应用,每个租户的数据是隔离的。以下是实现动态 tenant 的一种常见方法:
使用 ThreadLocal 存储当前租户信息:
在 MyBatis 的 Mapper XML 文件中编写动态 SQL:
<if>
标签来判断当前线程的租户信息是否存在,如果存在则将其作为参数传递给 SQL 语句。tenantId
,可以在 SQL 语句中使用 ${tenantId}
作为参数。<select id="selectUserByTenantId" parameterType="int" resultType="User">
SELECT * FROM users WHERE tenant_id = #{tenantId}
</select>
在 Service 层调用 Mapper 方法:
public User getUserByIdAndTenant(int userId) {
// 从 ThreadLocal 中获取租户 ID
int tenantId = TenantContext.getCurrentTenantId();
// 调用 Mapper 方法
User user = userMapper.selectUserByTenantId(tenantId, userId);
return user;
}
清理 ThreadLocal:
public class TenantContext {
private static final ThreadLocal<Integer> currentTenant = new ThreadLocal<>();
public static void setCurrentTenantId(int tenantId) {
currentTenant.set(tenantId);
}
public static int getCurrentTenantId() {
return currentTenant.get();
}
public static void clear() {
currentTenant.remove();
}
}
在过滤器中:
public class TenantFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在请求进入时设置租户信息
int tenantId = getTenantIdFromRequest(request);
TenantContext.setCurrentTenantId(tenantId);
try {
chain.doFilter(request, response);
} finally {
// 在请求结束时清理租户信息
TenantContext.clear();
}
}
private int getTenantIdFromRequest(ServletRequest request) {
// 根据请求头或其他方式获取租户信息
return 1; // 示例返回值
}
}
通过以上步骤,可以在 MyBatis 中实现动态 tenant 功能。需要注意的是,这种方法在单个请求内是有效的,因为 ThreadLocal 是线程局部变量。如果应用是多线程的,需要确保在每个线程中都正确地设置和清理租户信息。