如何在 spring 引导休眠多租户应用程序中使用 C3P0 来管理连接池?
How to use C3P0 in a spring boot hibernate multi tenant application to manage connection pool?
我正在尝试使用 hibernate 的 MultiTenantConnectionProvider 和 CurrentTenantIdentifierResolver 实现多租户应用程序。我不确定 hibernate 是如何管理池的,以及将它留给 Hibernate 是否是一个好习惯。我可以在这个多租户应用程序中使用 C3P0 吗?
这是我的初始代码:
@Bean(name = "dataSources" )
public Map<String, DataSource> dataSources() {
Map<String, DataSource> result = new HashMap<>();
for (DataSourceProperties dsProperties : this.multiTenantProperties.getDataSources()) {
DataSourceBuilder factory = DataSourceBuilder
.create()
.url(dsProperties.getUrl())
.username(dsProperties.getUsername())
.password(dsProperties.getPassword())
.driverClassName(dsProperties.getDriverClassName());
result.put(dsProperties.getTenantId(), factory.build());
}
return result;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(MultiTenantConnectionProvider DataSourceMultiTenantConnectionProviderImpl ,
CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
Map<String, Object> hibernateProps = new LinkedHashMap<>();
hibernateProps.putAll(this.jpaProperties.getProperties());
hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, TenantIdentifierResolverImpl );
// No dataSource is set to resulting entityManagerFactoryBean
LocalContainerEntityManagerFactoryBean result = new LocalContainerEntityManagerFactoryBean();
result.setPackagesToScan(new String[] { Test.class.getPackage().getName() });
result.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
result.setJpaPropertyMap(hibernateProps);
return result;
}
这是在休眠中配置的连接提供程序
public class DataSourceMultiTenantConnectionProviderImpl extends
AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 1L;
@Autowired
private Map<String, DataSource> dataSources;
@Override
protected DataSource selectAnyDataSource() {
return this.dataSources.values().iterator().next();
}
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
return this.dataSources.get(tenantIdentifier);
}
}
这是提供给休眠的租户解析器
public class TenantIdentifierResolverImpl implements
CurrentTenantIdentifierResolver {
private static String DEFAULT_TENANT_ID = "tenant_1";
@Override
public String resolveCurrentTenantIdentifier() {
String currentTenantId = TenantContext.getTenantId();
return (currentTenantId != null) ? currentTenantId : DEFAULT_TENANT_ID;
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
这里如何处理连接池?
您可能需要将数据源 bean 更改为:
@Bean(name = "dataSources" )
public Map<String, ComboPooledDataSource> dataSources() throws PropertyVetoException {
Map<String, ComboPooledDataSource> result = new HashMap<>();
for (DataSourceProperties dsProperties : this.multiTenantProperties.getDataSources()) {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(dsProperties.getDriverClassName());
ds.setJdbcUrl(dsProperties.getUrl());
ds.setUser(dsProperties.getUsername());
ds.setPassword(dsProperties.getPassword());
ds.setInitialPoolSize(5);
ds.setMinPoolSize(1);
ds.setAcquireIncrement(1);
ds.setMaxPoolSize(5);
result.put(dsProperties.getTenantId(), ds);
}
return result;
}
并将此方法添加到您的 DataSourceMultiTenantConnectionProviderImpl
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
return this.dataSources.get(tenantIdentifier).getConnection();
}
这应该足以启动使用 C3P0 的连接池。
我正在尝试使用 hibernate 的 MultiTenantConnectionProvider 和 CurrentTenantIdentifierResolver 实现多租户应用程序。我不确定 hibernate 是如何管理池的,以及将它留给 Hibernate 是否是一个好习惯。我可以在这个多租户应用程序中使用 C3P0 吗?
这是我的初始代码:
@Bean(name = "dataSources" )
public Map<String, DataSource> dataSources() {
Map<String, DataSource> result = new HashMap<>();
for (DataSourceProperties dsProperties : this.multiTenantProperties.getDataSources()) {
DataSourceBuilder factory = DataSourceBuilder
.create()
.url(dsProperties.getUrl())
.username(dsProperties.getUsername())
.password(dsProperties.getPassword())
.driverClassName(dsProperties.getDriverClassName());
result.put(dsProperties.getTenantId(), factory.build());
}
return result;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(MultiTenantConnectionProvider DataSourceMultiTenantConnectionProviderImpl ,
CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
Map<String, Object> hibernateProps = new LinkedHashMap<>();
hibernateProps.putAll(this.jpaProperties.getProperties());
hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, TenantIdentifierResolverImpl );
// No dataSource is set to resulting entityManagerFactoryBean
LocalContainerEntityManagerFactoryBean result = new LocalContainerEntityManagerFactoryBean();
result.setPackagesToScan(new String[] { Test.class.getPackage().getName() });
result.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
result.setJpaPropertyMap(hibernateProps);
return result;
}
这是在休眠中配置的连接提供程序
public class DataSourceMultiTenantConnectionProviderImpl extends
AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 1L;
@Autowired
private Map<String, DataSource> dataSources;
@Override
protected DataSource selectAnyDataSource() {
return this.dataSources.values().iterator().next();
}
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
return this.dataSources.get(tenantIdentifier);
}
}
这是提供给休眠的租户解析器
public class TenantIdentifierResolverImpl implements
CurrentTenantIdentifierResolver {
private static String DEFAULT_TENANT_ID = "tenant_1";
@Override
public String resolveCurrentTenantIdentifier() {
String currentTenantId = TenantContext.getTenantId();
return (currentTenantId != null) ? currentTenantId : DEFAULT_TENANT_ID;
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
这里如何处理连接池?
您可能需要将数据源 bean 更改为:
@Bean(name = "dataSources" )
public Map<String, ComboPooledDataSource> dataSources() throws PropertyVetoException {
Map<String, ComboPooledDataSource> result = new HashMap<>();
for (DataSourceProperties dsProperties : this.multiTenantProperties.getDataSources()) {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(dsProperties.getDriverClassName());
ds.setJdbcUrl(dsProperties.getUrl());
ds.setUser(dsProperties.getUsername());
ds.setPassword(dsProperties.getPassword());
ds.setInitialPoolSize(5);
ds.setMinPoolSize(1);
ds.setAcquireIncrement(1);
ds.setMaxPoolSize(5);
result.put(dsProperties.getTenantId(), ds);
}
return result;
}
并将此方法添加到您的 DataSourceMultiTenantConnectionProviderImpl
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
return this.dataSources.get(tenantIdentifier).getConnection();
}
这应该足以启动使用 C3P0 的连接池。