在MultiTenantConnectionProvider中抛出异常会耗尽连接池中的连接

时间:2017-12-31 12:17:52

标签: spring hibernate spring-boot multi-tenant

我在MySQL中使用模式的多租户,

class SchemaPerTenantConnectionProvider : MultiTenantConnectionProvider {

  @Autowired
  private lateinit var dataSource: DataSource

  @Throws(SQLException::class)
  override fun getAnyConnection() = this.dataSource.connection

  @Throws(SQLException::class)
  override fun releaseAnyConnection(connection: Connection) {
    connection.close()
  }

  @Throws(SQLException::class)
  override fun getConnection(tenantIdentifier: String): Connection {
    val connection = this.anyConnection
    try {
      connection.createStatement().execute("USE $tenantIdentifier ")
    } catch (e: SQLException) {
      throw SQLException("Could not alter JDBC connection to schema [$tenantIdentifier]")
    }

    return connection
  }
...
}

我的连接池大小为10,现在如果任何无效tenantIdentifier被传递10次,则10个连接用尽,此应用程序无法获取任何连接。

尝试投掷Exception, HibernateException并没有帮助。使用与default schema的连接将获取错误的结果。有没有办法在getConnection()中处理这种情况,以免耗尽连接限制?

2 个答案:

答案 0 :(得分:2)

以下配置应该有效,覆盖public void releaseConnection(String tenantIdentifier, Connection connection)将确保连接被释放回连接池。

   public class MultiTenantConnectionProviderImpl
            implements MultiTenantConnectionProvider, Stoppable {
        private final ConnectionProvider connectionProvider = ConnectionProviderUtils.buildConnectionProvider( "master" );

        @Override
        public Connection getAnyConnection() throws SQLException {
            return connectionProvider.getConnection();
        }

        @Override
        public void releaseAnyConnection(Connection connection) throws SQLException {
            connectionProvider.closeConnection( connection );
        }

        @Override
        public Connection getConnection(String tenantIdentifier) throws SQLException {
            final Connection connection = getAnyConnection();
            try {
                connection.createStatement().execute( "USE " + tenanantIdentifier );
            }
            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 {
            try {
                connection.createStatement().execute( "USE master" );
            }
            catch ( SQLException e ) {
                // on error, throw an exception to make sure the connection is not returned to the pool.
                // your requirements may differ
                throw new HibernateException(
                        "Could not alter JDBC connection to specified schema [" +
                                tenantIdentifier + "]",
                        e
                );
            }
            connectionProvider.closeConnection( connection );
        }

        ...
    }

接下来,在spring boot中微调数据源配置:

# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

参考:Working with datasources

如果问题仍然存在,请继续使用数据源连接池机制支持,例如Hikari等。

答案 1 :(得分:0)

关闭连接,如果错误解决了问题。

@Throws(SQLException::class)
  override fun getConnection(tenantIdentifier: String): Connection {
    val connection = this.anyConnection
    try {
      connection.createStatement().execute("USE $tenantIdentifier ")
    } catch (e: SQLException) {
      connection.close()
      throw SQLException("Could not alter JDBC connection to schema [$tenantIdentifier]")
    }

    return connection
  }