我正在尝试使用单独的架构方法设置多租户应用程序。
我正在使用JPA和Hibernate 4实现。
就像在这个非常有用的ben75中所说的@ thread一样,有很多方法可以管理连接(每个租户的共享或自己的连接)。
我已经基于单独的架构开发了第一个解决方案,但是使用了像thread这样的共享连接池。 这样做很好,但我认为如果每个租户都有自己的连接,那就更好了,因为租户不能降低其他租户的性能。
这种方法似乎与单独的数据库方法类似,但我不知道如何创建连接(使用C3P0或其他东西?)。在hibernate文档中,他们使用类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 ?
}
关于@ Ben75的answer,他说我必须从文件中获取默认的hibernate和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);
}
}
它适用于Oracle,但我不知道这是否是一个很好的实现...
此外,它不知道为什么它在我的嵌入式H2数据库上不起作用,查询总是在公共默认模式上执行,即使更改用户没有权利。
编辑2:
最后,在H2数据库中,我必须添加:
settings.put("hibernate.connection.url", "jdbc:h2:./db;INIT=SET SCHEMA " + tenantIdentifier);