2017-02-21 20 views
0

Я работаю над реализацией multitenancy = "DATABASE", то есть пул одиночных подключений с каждой базой данных/схемой для каждого арендатора (база данных и схема mysql являются синонимами).Mysql with Hibernate AbstractMultiTenantConnectionProvider с C3P0ConnectionProvider throws GenericJDBCException: Не удалось открыть соединение

Я получил 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-адреса подключения.

Кто-нибудь еще столкнулся с этой проблемой?

ответ

0

я в конечном итоге реализации 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; 
} 
}