在 MyBatis 中設(shè)置 tenant 標(biāo)識(shí),通常是為了實(shí)現(xiàn)多租戶應(yīng)用的數(shù)據(jù)隔離。以下是一些常見的方法來實(shí)現(xiàn)這一功能:
ThreadLocal
是 Java 提供的一個(gè)線程本地變量,它可以讓變量與線程綁定,實(shí)現(xiàn)線程數(shù)據(jù)的隔離。
步驟:
mybatis-config.xml
),添加一個(gè)類型處理器(TypeHandler)來處理 tenant 的類型轉(zhuǎn)換。<typeHandlers>
<typeHandler handler="com.example.TenantTypeHandler" javaType="java.lang.String" jdbcType="VARCHAR"/>
</typeHandlers>
TenantTypeHandler
類,用于處理 tenant 的存儲(chǔ)和讀取。public class TenantTypeHandler extends BaseTypeHandler<String> {
private static final ThreadLocal<String> currentTenant = new InheritableThreadLocal<>();
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
currentTenant.set(parameter);
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
public static String getCurrentTenant() {
return currentTenant.get();
}
public static void clear() {
currentTenant.remove();
}
}
TenantTypeHandler.getCurrentTenant()
獲取當(dāng)前線程的 tenant 標(biāo)識(shí),并在 SQL 中使用該標(biāo)識(shí)進(jìn)行數(shù)據(jù)隔離。示例:
String sql = "SELECT * FROM ${tenant}.table_name WHERE tenant = #{tenant}";
在 MyBatis 的 Mapper XML 文件中,可以使用 #{}
來引用方法參數(shù),這樣 MyBatis 會(huì)自動(dòng)將方法參數(shù)傳遞給 SQL 語句中的 ${tenant}
占位符。
另一種方法是使用數(shù)據(jù)庫(kù)視圖或存儲(chǔ)過程來封裝數(shù)據(jù)查詢,并在其中根據(jù) tenant 標(biāo)識(shí)過濾數(shù)據(jù)。
步驟:
示例(視圖):
CREATE VIEW tenant_data AS
SELECT * FROM original_table
WHERE tenant_id = #{tenantId};
示例(存儲(chǔ)過程):
DELIMITER //
CREATE PROCEDURE GetTenantData(IN tenantId INT)
BEGIN
SELECT * FROM original_table WHERE tenant_id = tenantId;
END //
DELIMITER ;
在 MyBatis 的 Mapper XML 文件中,可以調(diào)用該存儲(chǔ)過程:
<select id="selectTenantData" parameterType="int" statementType="CALLABLE">
{call GetTenantData(#{tenantId})}
</select>
ThreadLocal
存儲(chǔ) tenant 信息時(shí),需要注意線程安全問題,避免數(shù)據(jù)泄露或被意外修改。