MyBatis在多租户应用程序中出现

时间:2012-02-24 11:52:44

标签: spring ibatis multi-tenant mybatis

您需要一些帮助在多租户中使用MyBatis弹簧 申请......

有可能吗?特别是因为我不知道如何 可以使用sqlSessionFactory配置“MapperScannerConfigurer” 运行。

3 个答案:

答案 0 :(得分:0)

可以使用工厂创建租户范围的数据源,并将其连接到由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>

和TenantDataSourceFactory:

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范围是自定义范围,其中包含作为范围bean映射的租户名称的Map<String, Map<String, Object>>。它根据当前租户的概念发送给给定的租户。

答案 1 :(得分:0)

Spring有AbstractRoutingDataSource来处理这个问题

http://spring.io/blog/2007/01/23/dynamic-datasource-routing/

答案 2 :(得分:0)

这是使用插件(也称为拦截器)切换“模式”或“目录”的另一种方法。

根据您使用的数据库,每个租户都有自己的数据库或架构。 一些例子:

  • MySQL:每个租户都有其自己的“数据库”,插件应调用setCatalog
  • Oracle:每个租户都有其自己的“模式”,并且插件应调用setSchema
  • SQL Server:每个租户都有自己的“数据库”,并且插件应调用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的demo