Recently, the project was restructured. The original project's multi-tenancy based on mybatis cannot be used. The jpa that needs to be migrated is uploaded. I originally wanted to try it.
spring.jpa.properties.hibernate.multiTenancy=DISCRIMINATOR for discovery has not been implemented yet
Consider using jpa filters to intercept the incoming sql and then insert it into the database.
1. All tenant IDs are obtained through the head parameter, and the interceptor is established and placed in the local variable of the thread.
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantId = request.getHeader("TenantId");
System.out.println("-tenantId:-" + tenantId);
TenantContext.setTenantId(StringUtils.isBlank(tenantId) ? TenantConst.DEFAULT_TENANTID : tenantId);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
TenantContext.remove();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
2. The context that stores the tenant ID
public class TenantContext {
// 构造方法私有化
private TenantContext() {
}
private static final ThreadLocal<String> context = new ThreadLocal<>();
/**
* 存放租户信息
*
* @param tenantInfo
*/
public static void setTenantId(String tenantInfo) {
context.set(tenantInfo);
}
/**
* 获取租户信息
*
* @return
*/
public static String getTenantId() {
return context.get();
}
/**
* 清除当前线程内引用,防止内存泄漏
*/
public static void remove() {
context.remove();
}
}
3.jpa filter
public class MyJpaInterceptor implements StatementInspector {
/**
* 当前数据库的方言
*/
private String dialect="mysql";
/**
* 多租户字段名称
*/
private String tenantIdField="tenant_id";
/**
* 需要识别多租户字段的表名称列表 --目前先写死
*/
private Set<String> tableSet = new HashSet<>();
/**
* sql语句工具
*/
private SqlConditionUtil sqlConditionUtil;
/**
* 给sql语句where添加租户id过滤条件
*
* @param sql 要添加过滤条件的sql语句
* @param tenantId 当前的租户id
* @return 添加条件后的sql语句
*/
private String addTenantCondition(String sql, String tenantId) {
if (StringUtils.isBlank(sql) || StringUtils.isBlank(tenantId)) {
return sql;
}
List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dialect);
if (statementList == null || statementList.size() == 0) {
return sql;
}
SQLStatement sqlStatement = statementList.get(0);
/**
* 多租户条件字段决策器
*/
ITableFieldConditionDecision conditionDecision = new ITableFieldConditionDecision() {
@Override
public boolean isAllowNullValue() {
return false;
}
@Override
public boolean adjudge(String tableName, String fieldName) {
tableSet.add("t_book");
if (tableSet != null && tableSet.contains(tableName)) {
return true;
}
return false;
}
};
sqlConditionUtil = new SqlConditionUtil(conditionDecision);
sqlConditionUtil.addStatementCondition(sqlStatement, tenantIdField, tenantId);
return SQLUtils.toSQLString(statementList, dialect);
}
@Override
public String inspect(String s) {
System.out.println("sql拦截器:-----"+s);
String tenantId = TenantContext.getTenantId();
System.out.println("---tenantId:------->" + tenantId);
//租户id为空时不做处理
if (StringUtils.isBlank(tenantId)) {
return s;
}
//把新sql设置到boundSql
String newSql = addTenantCondition(s, tenantId);
System.out.println("--------newSql:---" + newSql);
return newSql;
}
}
4. Entity class
@Entity(name = "t_book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String author;
@Column(nullable = false, updatable = false)
private String tenantId;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", tenantId='" + tenantId + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}
5. Modify the configuration file xxx to your own package name
6. Test