2016-12-24 33 views
1

私はユーザーがサインアップし、新しいデータベースが作成されるシナリオを持っています。このデータベースは、サインアッププロセスが完了するとすぐにMultiTenantConnectionProvider(接続プール)に追加する必要があります。すべてが正常に動作していますが、データソースをMultiTenantConnectionProviderに動的に追加することはできません。マルチテナント用Springマルチテナント:ユーザー追加時にMultiTenantConnectionProviderにデータソースを動的に追加

Hibernateの設定:MyMultiTenantConnectionProviderため

 <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
       <prop key="hibernate.multiTenancy">DATABASE</prop> 
       <prop key="hibernate.tenant_identifier_resolver">com.company.multitenancy.MyCurrentTenantIdentifierResolverImpl 
       </prop> 
       <prop key="hibernate.multi_tenant_connection_provider">com.company.multitenancy.MyMultiTenantConnectionProvider 
       </prop> 
      </props> 
     </property> 

コード:MyCurrentTenantIdResolverため

package com.company.multitenancy; 

import java.sql.DriverManager; 
import java.sql.ResultSet; 
import java.sql.Statement; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 

import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; 
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;  
import com.termbreak.constant.ConstantStrings; 

public class MyMultiTenantConnectionProvider extends 
     AbstractMultiTenantConnectionProvider { 
    private static final long serialVersionUID = -8669630427906544663L; 
    private HashMap<String, ConnectionProviderImpl> connProviderMap = new HashMap<String, ConnectionProviderImpl>(); 

    public MyMultiTenantConnectionProvider() { 
     List<String> providerNames = new ArrayList<String>(); 
     providerNames.add(ConstantStrings.DEFAULT_TENANT_ID); 
     try { 
      String sqlUrl = "jdbc:mysql://localhost:3306/"+ConstantStrings.DEFAULT_TENANT_ID; 
      Class.forName("com.mysql.jdbc.Driver"); 
      java.sql.Connection conn = DriverManager.getConnection(sqlUrl, 
        "root", "root"); 
      Statement st = conn.createStatement(); 
      ResultSet rs = st 
        .executeQuery("select DISTINCT TENANT_ID from User"); 
      while (rs.next()) { 
       String tenantId = rs.getString(1); 
       providerNames.add(tenantId); 
      } 
      conn.close(); 
     } catch (Exception e) { 
      System.err.println("Got an exception! "); 
      System.err.println(e.getMessage()); 
     } 
     for (String providerName : providerNames) { 
      connProviderMap.put(providerName, new ConnectionProviderImpl(
        providerName)); 
     } 
    } 

    public ConnectionProvider getAnyConnectionProvider() { 
     System.out 
       .println("inside MultiTenantConnectionProvider::getAnyConnectionProvider"); 
     return connProviderMap.get(ConstantStrings.DEFAULT_TENANT_ID); 
    } 

    public ConnectionProvider selectConnectionProvider(String tenantId) { 
     ConnectionProvider connectionProvider = connProviderMap.get(tenantId); 
     if (connectionProvider == null) 
      connectionProvider = new ConnectionProviderImpl(ConstantStrings.DEFAULT_TENANT_ID); 
     return connectionProvider; 
    } 
} 

コード:MyConnectionProviderImplため

package com.company.multitenancy; 

import org.hibernate.context.spi.CurrentTenantIdentifierResolver; 

import com.termbreak.constant.ConstantStrings; 

public class MyCurrentTenantIdentifierResolverImpl implements 
     CurrentTenantIdentifierResolver { 
    public ThreadLocal<String> _tenantIdentifier = new ThreadLocal<String>(); 
    public String DEFAULT_TENANT_ID = ConstantStrings.DEFAULT_TENANT_ID; 

    public String resolveCurrentTenantIdentifier() { 
     System.out.println("from inside resolveCurrentTenantIdentifier...."); 
     String tenantId = _tenantIdentifier.get(); 
     if (tenantId == null) 
      tenantId = DEFAULT_TENANT_ID; 
     System.out.println("threadlocal tenant id =" + tenantId); 
     return tenantId; 
    } 

    public boolean validateExistingCurrentSessions() { 
     return true; 
    } 

} 

コード:

package com.company.multitenancy; 

import java.sql.Connection; 
import java.sql.SQLException; 

import org.apache.commons.dbcp2.BasicDataSource; 
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; 

public class ConnectionProviderImpl implements ConnectionProvider { 
    private static final long serialVersionUID = -8926112316994338537L; 
    private BasicDataSource basicDataSource; 

    public ConnectionProviderImpl(String database){ 
     //this should be read from properties file 
     basicDataSource = new BasicDataSource(); 
     basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
     basicDataSource.setUrl("jdbc:mysql://localhost:3306/"+database); 
     basicDataSource.setUsername("root"); 
     basicDataSource.setPassword("root"); 
     basicDataSource.setInitialSize(2); 
    } 
    public boolean isUnwrappableAs(Class arg0) { 
     return false; 
    } 
    public Object unwrap(Class arg0) { 
     return null; 
    } 
    public void closeConnection(Connection arg0) throws SQLException { 
     arg0.close(); 
    } 
    public Connection getConnection() throws SQLException { 
     return basicDataSource.getConnection(); 
    } 
    public boolean supportsAggressiveRelease() { 
     return false; 
    } 
} 

私が使用しています特定のテナントに接続するには:

sessionFactory.withOptions().tenantIdentifier(tenantId).openSession(); 

答えて

0

あなたの構成はConnectionProviderImplの実装を除いて正しいと思われます。この実装では、テナント識別子をhibernateに提供する必要があります。 AbstractDataSourceBasedMultiTenantConnectionProviderImplを実装し、使用しているHibernateのバージョンに応じてgetConnection()またはselectDataSource()をオーバーライドする必要があります。 Hibernateユーザガイドhttps://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/ch16.htmlの例16.3とこの投稿http://www.ticnfae.co.uk/blog/2014/07/16/hibernate-multi-tenancy-with-spring/に従うことをお勧めします。

+0

すべてのものがこのコードで完璧に動作しています。私が今直面している唯一の問題は、ユーザーが新しいデータベースにサインアップしてそのユーザー用に作成された新しいテナントIDが生成されたときです。このテナントIDは私ができない接続プールにあります。任意のポインタが役に立ちます –

+0

ConnectionProviderを直接実装する代わりに、AbstractDataSourceBasedMultiTenantConnectionProviderImplを拡張してselectDataSource()をオーバーライドしてみることができます。 MyCurrentTenantIdentifierResolverImpl#resolveCurrentTenantIdentifier()はテナント識別子を返します。このテナント識別子は、AbstractDataSourceBasedMultiTenantConnectionProviderImpl#selectDataSource(String tenantIdentifier)で使用されます。 –

関連する問題