Mysql 使用 Hibernate AbstractMultiTenantConnectionProvider 使用 C3P0ConnectionProvider 抛出 GenericJDBCException:无法打开连接
Mysql with Hibernate AbstractMultiTenantConnectionProvider with C3P0ConnectionProvider throws GenericJDBCException: Could not open connection
我正在努力实现多租户="DATABASE",即每个租户的单个连接池database/schema(mysql 数据库和模式是同义词)。
我有MultiTenantConnectionProviderImpl.java
public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider implements
ServiceRegistryAwareService {
private static final long serialVersionUID = 1234567890L;
private final HashMap<String, C3P0ConnectionProvider> connProviderMap = new HashMap<>();
private Map<String, String> originalSettings;
private ServiceRegistryImplementor serviceRegistry;
public MultiTenantConnectionProviderImpl() {
}
@Override
protected C3P0ConnectionProvider getAnyConnectionProvider() {
return selectConnectionProvider(TenantContext.getTenantId());
}
@Override
protected C3P0ConnectionProvider selectConnectionProvider(String tenantId) {
if (tenantId == null || !tenantId.equals(TenantContext.getTenantId())) {
throw new TenantStateException(
"Cannot get connection. Cause: tenant_id is not defined.");
}
C3P0ConnectionProvider connectionProvider = connProviderMap.get(tenantId);
if (connectionProvider == null) {
// create the new connection and register it
Map<String, String> settings = new HashMap<>(originalSettings);
// alter connection by changing user / password of the connection
Properties properties = new PropertiesBuilder().withScope("database").build();
settings.put("hibernate.connection.user", DatabaseConnectionProperties.getUser());
settings.put("hibernate.connection.password", DatabaseConnectionProperties.getPassword());
settings.put("hibernate.connection.url", DatabaseConnectionProperties.getConnectionUrl());
settings.put("hibernate.connection.driver_class", properties.getProperty("hibernate.connection.driver_class"));
connectionProvider = new C3P0ConnectionProvider();
connectionProvider.injectServices(serviceRegistry);
connectionProvider.configure(settings);
connProviderMap.put(tenantId, 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);
connProviderMap.put(TenantContext.getTenantId(), connectionProvider);
}
}
并且连接用户如下
String.format("jdbc:mysql://%s/%s", databaseHost, databaseName)
失败
rg.hibernate.exception.GenericJDBCException: Could not open connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
...
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:297) ~[hibernate-core-4.1.12.Final.jar:4.1.12.Final]
... 43 common frames omitted
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
我试图覆盖 getConnection(String tenantId) 以执行 "use tenantId" 以获得正确的数据库。但是它没有帮助,我恢复到使用连接 url 指定数据库的原始方式。
还有其他人遇到过这个问题吗?
我最终实现了 MultiTenantConnectionProvider,首先连接到默认模式,然后将模式更改为租户模式
public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider,
ServiceRegistryAwareService {
private static final long serialVersionUID = 12345567890;
C3P0ConnectionProvider connectionProvider = null;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map<String, String> originalSettings = serviceRegistry
.getService(ConfigurationService.class).getSettings();
connectionProvider = new C3P0ConnectionProvider();
connectionProvider.injectServices(serviceRegistry);
connectionProvider.configure(originalSettings);
}
@Override
public Connection getAnyConnection() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
final Connection connection = DriverManager.getConnection(
DatabaseConnectionProperties.getConnectionUrl(),
DatabaseConnectionProperties.getUser(), DatabaseConnectionProperties.getPassword());
return connection;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return connectionProvider.getConnection();
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
try {
connection.createStatement().execute("use default_tenant");
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [public]", e);
}
connectionProvider.closeConnection(connection);
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute("use " + tenantIdentifier);
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema ["
+ tenantIdentifier + "]", e);
}
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection)
throws SQLException {
releaseAnyConnection(connection);
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return false;
}
@Override
public <T> T unwrap(Class<T> unwrapType) {
return null;
}
}
我正在努力实现多租户="DATABASE",即每个租户的单个连接池database/schema(mysql 数据库和模式是同义词)。
我有MultiTenantConnectionProviderImpl.java
public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider implements
ServiceRegistryAwareService {
private static final long serialVersionUID = 1234567890L;
private final HashMap<String, C3P0ConnectionProvider> connProviderMap = new HashMap<>();
private Map<String, String> originalSettings;
private ServiceRegistryImplementor serviceRegistry;
public MultiTenantConnectionProviderImpl() {
}
@Override
protected C3P0ConnectionProvider getAnyConnectionProvider() {
return selectConnectionProvider(TenantContext.getTenantId());
}
@Override
protected C3P0ConnectionProvider selectConnectionProvider(String tenantId) {
if (tenantId == null || !tenantId.equals(TenantContext.getTenantId())) {
throw new TenantStateException(
"Cannot get connection. Cause: tenant_id is not defined.");
}
C3P0ConnectionProvider connectionProvider = connProviderMap.get(tenantId);
if (connectionProvider == null) {
// create the new connection and register it
Map<String, String> settings = new HashMap<>(originalSettings);
// alter connection by changing user / password of the connection
Properties properties = new PropertiesBuilder().withScope("database").build();
settings.put("hibernate.connection.user", DatabaseConnectionProperties.getUser());
settings.put("hibernate.connection.password", DatabaseConnectionProperties.getPassword());
settings.put("hibernate.connection.url", DatabaseConnectionProperties.getConnectionUrl());
settings.put("hibernate.connection.driver_class", properties.getProperty("hibernate.connection.driver_class"));
connectionProvider = new C3P0ConnectionProvider();
connectionProvider.injectServices(serviceRegistry);
connectionProvider.configure(settings);
connProviderMap.put(tenantId, 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);
connProviderMap.put(TenantContext.getTenantId(), connectionProvider);
}
}
并且连接用户如下
String.format("jdbc:mysql://%s/%s", databaseHost, databaseName)
失败
rg.hibernate.exception.GenericJDBCException: Could not open connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
...
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:297) ~[hibernate-core-4.1.12.Final.jar:4.1.12.Final]
... 43 common frames omitted
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
我试图覆盖 getConnection(String tenantId) 以执行 "use tenantId" 以获得正确的数据库。但是它没有帮助,我恢复到使用连接 url 指定数据库的原始方式。
还有其他人遇到过这个问题吗?
我最终实现了 MultiTenantConnectionProvider,首先连接到默认模式,然后将模式更改为租户模式
public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider,
ServiceRegistryAwareService {
private static final long serialVersionUID = 12345567890;
C3P0ConnectionProvider connectionProvider = null;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map<String, String> originalSettings = serviceRegistry
.getService(ConfigurationService.class).getSettings();
connectionProvider = new C3P0ConnectionProvider();
connectionProvider.injectServices(serviceRegistry);
connectionProvider.configure(originalSettings);
}
@Override
public Connection getAnyConnection() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
final Connection connection = DriverManager.getConnection(
DatabaseConnectionProperties.getConnectionUrl(),
DatabaseConnectionProperties.getUser(), DatabaseConnectionProperties.getPassword());
return connection;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return connectionProvider.getConnection();
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
try {
connection.createStatement().execute("use default_tenant");
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [public]", e);
}
connectionProvider.closeConnection(connection);
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute("use " + tenantIdentifier);
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema ["
+ tenantIdentifier + "]", e);
}
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection)
throws SQLException {
releaseAnyConnection(connection);
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return false;
}
@Override
public <T> T unwrap(Class<T> unwrapType) {
return null;
}
}