[英]MyBatis spring in a multi tenant application
嗨,在多租戶應用程序中使用 MyBatis spring 需要一些幫助......
是否有可能 ? 特別是因為我沒有看到如何在運行時使用 sqlSessionFactory 配置“MapperScannerConfigurer”。
可以使用工廠創建租戶范圍的數據源並將其連接到由 mybatis-spring 生成的映射器使用的 SqlSessionFactory。 這是相關的 app-context.xml 部分
<bean id="dataSourceFactory" class="com.myapp.TenantDataSourceFactory"
depends-on="tenant" scope="singleton"/>
<bean id="dataSource" factory-bean="dataSourceFactory" factory-method="getObject"
destroy-method="close" scope="tenant" >
<aop:scoped-proxy/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:myBatisConfig.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.myapp" />
<property name="annotationClass" value="com.myapp.mapper.Mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
和租戶數據源工廠:
public class TenantDataSourceFactory {
@Autowired Tenant tenant;
public DataSource getObject() throws Exception {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl(String.format("jdbc:postgresql://%s:%s/%s",
tenant.getDbHost(), tenant.getDbPort(), tenant.getDbName()));
ds.setUsername(tenant.getDbUser());
ds.setPassword(tenant.getDbPassword());
return ds;
}
}
tenant
范圍是包含Map<String, Map<String, Object>>
自定義范圍,它是范圍 bean 映射的租戶名稱。 它根據當前租戶的概念分派給給定的租戶。
Spring 有 AbstractRoutingDataSource 來處理這個問題
http://spring.io/blog/2007/01/23/dynamic-datasource-routing/
這是使用插件(又名攔截器)切換“模式”或“目錄”的另一種方法。
根據您使用的數據庫,每個租戶都有自己的數據庫或架構。 幾個例子:
setCatalog
。setSchema
。setCatalog
。假設您通過 ThreadLocal 傳遞租戶 ID,這里是一個示例插件實現。
import java.sql.Connection;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
@Intercepts(
@Signature(
type = StatementHandler.class,
method = "prepare",
args = { Connection.class, Integer.class }))
public class MultiTenantInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
Connection con = (Connection) args[0];
con.setSchema(TenantIdHolder.getTenantId());
// con.setCatalog(TenantIdHolder.getTenantId());
return invocation.proceed();
}
}
TenantIdHolder
只是一個ThreadLocal
持有者。
public class TenantIdHolder {
private static ThreadLocal<String> value = new ThreadLocal<>();
public static void setTenantId(String tenantId) {
value.set(tenantId);
}
public static String getTenantId() {
return value.get();
}
}
這是一個使用 HSQLDB 的演示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.