使用Hibernate在多租户应用程序中管理连接池

asc*_*ott 6 java hibernate c3p0 multi-tenant

我正在尝试使用单独的架构方法设置多租户应用程序。

我在Hibernate 4实现中使用JPA。

就像在这个非常有用的线程中所说的@ ben75一样,有很多方法可以管理连接(每个租户共享或拥有自己的连接)。

我已经开发了基于单独模式的第一个解决方案,但是具有一个共享的连接池,例如该线程。这很好,但我认为如果每个租户都可以拥有自己的连接,那会更好,因为一个租户不会降低其他租户的表现。

这种方法似乎类似于单独的数据库方法,但是我不知道如何创建连接(使用C3P0或其他方法?)。在休眠文档中,他们使用类ConnectionProviderUtils,但是我真的不知道该类做了什么。

MultiTenantConnectionProviderImpl

public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider {  

private C3P0ConnectionProvider connectionProvider = null;

@Override
protected ConnectionProvider getAnyConnectionProvider() {
    // my main question is here 

}

@Override
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
   // and here - how create a new connection ?
}
Run Code Online (Sandbox Code Playgroud)

关于@ Ben75 的答案,他说我必须从文件中获取默认的休眠和c3po配置属性并更改架构。或者,如果租户有其他用户,也可能是用户名/密码。

你知道我该怎么做吗?是否有一些用于读取persistence.xml并创建连接的类?

我已经找到了使用JNDI服务获取良好数据源的独立数据库方法的示例,但是在我的应用程序中却没有(不是完整的Java EE)。

编辑

在Oracle上似乎有一个实现可行的实现(在此示例中,用户名/密码与tenantId相同):

public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider
    implements ServiceRegistryAwareService {

     private Map<String, C3P0ConnectionProvider> connectionPool = new HashMap<>();
     private Map<String, String> originalSettings;
     private ServiceRegistryImplementor serviceRegistry;

     @Override
     protected ConnectionProvider getAnyConnectionProvider() {
         // return the default connection
         return connectionPool.get(TenantContext.get().getTenantId());
     }

     @Override
     protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
        C3P0ConnectionProvider connectionProvider = connectionPool.get(tenantIdentifier);
        if (connectionProvider == null) {
          // create the new connection and register it
          Map<String, String> settings = new HashMap<>(originalSettings);
          // alter connexion by changing user / password of the connection
          settings.put("hibernate.connection.user", tenantIdentifier);
          settings.put("hibernate.connection.password", tenantIdentifier);
          connectionProvider = new C3P0ConnectionProvider();
          connectionProvider.injectServices(serviceRegistry);
          connectionProvider.configure(settings);
          connectionPool.put(tenantIdentifier, connectionProvider);
        }
        return connectionProvider;
     }

     @Override
     public void injectServices(ServiceRegistryImplementor serviceRegistry) {
        this.serviceRegistry = serviceRegistry;
        originalSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
        C3P0ConnectionProvider connectionProvider = new C3P0ConnectionProvider();
        connectionProvider.injectServices(serviceRegistry);
        connectionProvider.configure(originalSettings);
        connectionPool.put(TenantContext.get().getTenantId(), connectionProvider);
     }
  }
Run Code Online (Sandbox Code Playgroud)

它在Oracle上运行良好,但我不知道这是否是一个很好的实现...

而且,它不知道为什么它不能在我的嵌入式H2 DB上运行,因此即使对更改用户无权,查询也总是在公共默认模式下执行。

编辑2:

最后,在H2数据库上,我必须添加以下内容:

settings.put("hibernate.connection.url", "jdbc:h2:./db;INIT=SET SCHEMA " + tenantIdentifier); 
Run Code Online (Sandbox Code Playgroud)