私はユーザーがサインアップし、新しいデータベースが作成されるシナリオを持っています。このデータベースは、サインアッププロセスが完了するとすぐに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();
すべてのものがこのコードで完璧に動作しています。私が今直面している唯一の問題は、ユーザーが新しいデータベースにサインアップしてそのユーザー用に作成された新しいテナントIDが生成されたときです。このテナントIDは私ができない接続プールにあります。任意のポインタが役に立ちます –
ConnectionProviderを直接実装する代わりに、AbstractDataSourceBasedMultiTenantConnectionProviderImplを拡張してselectDataSource()をオーバーライドしてみることができます。 MyCurrentTenantIdentifierResolverImpl#resolveCurrentTenantIdentifier()はテナント識別子を返します。このテナント識別子は、AbstractDataSourceBasedMultiTenantConnectionProviderImpl#selectDataSource(String tenantIdentifier)で使用されます。 –