在 MyBatis 中設置 tenant 標識,通常是為了實現多租戶應用的數據隔離。以下是一些常見的方法來實現這一功能:
ThreadLocal
是 Java 提供的一個線程本地變量,它可以讓變量與線程綁定,實現線程數據的隔離。
步驟:
mybatis-config.xml
),添加一個類型處理器(TypeHandler)來處理 tenant 的類型轉換。<typeHandlers>
<typeHandler handler="com.example.TenantTypeHandler" javaType="java.lang.String" jdbcType="VARCHAR"/>
</typeHandlers>
TenantTypeHandler
類,用于處理 tenant 的存儲和讀取。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()
獲取當前線程的 tenant 標識,并在 SQL 中使用該標識進行數據隔離。示例:
String sql = "SELECT * FROM ${tenant}.table_name WHERE tenant = #{tenant}";
在 MyBatis 的 Mapper XML 文件中,可以使用 #{}
來引用方法參數,這樣 MyBatis 會自動將方法參數傳遞給 SQL 語句中的 ${tenant}
占位符。
另一種方法是使用數據庫視圖或存儲過程來封裝數據查詢,并在其中根據 tenant 標識過濾數據。
步驟:
示例(視圖):
CREATE VIEW tenant_data AS
SELECT * FROM original_table
WHERE tenant_id = #{tenantId};
示例(存儲過程):
DELIMITER //
CREATE PROCEDURE GetTenantData(IN tenantId INT)
BEGIN
SELECT * FROM original_table WHERE tenant_id = tenantId;
END //
DELIMITER ;
在 MyBatis 的 Mapper XML 文件中,可以調用該存儲過程:
<select id="selectTenantData" parameterType="int" statementType="CALLABLE">
{call GetTenantData(#{tenantId})}
</select>
ThreadLocal
存儲 tenant 信息時,需要注意線程安全問題,避免數據泄露或被意外修改。