我有一个用户注册并为他们创建新数据库的场景。注册过程完成后,需要将此数据库添加到MultiTenantConnectionProvider(连接池)。一切正常,但无法将数据源动态添加到MultiTenantConnectionProvider。
多租户的Hibernate配置:
<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>
MyMultiTenantConnectionProvider的代码:
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;
}
}
MyCurrentTenantIdResolver的代码:
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;
}
}
MyConnectionProviderImpl的代码:
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 :(得分:1)
除了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/进行操作。