【问题标题】:Throwing exception in MultiTenantConnectionProvider, exhausts the connections in Connection Pool在 MultiTenantConnectionProvider 中引发异常,耗尽连接池中的连接
【发布时间】:2017-12-31 22:12:39
【问题描述】:

我在 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() 中处理这种情况,而不是耗尽连接限制?

【问题讨论】:

  • 我希望你也覆盖public void releaseConnection(String tenantIdentifier, Connection connection) 并在此处关闭连接

标签: spring hibernate spring-boot multi-tenant


【解决方案1】:

下面的配置应该可以工作,覆盖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 等。

【讨论】:

  • 感谢您的回答。实际上,正如您所提到的,我正在使用 HikariCP 并在 releaseConnection 中释放连接。这没有用。现在我尝试在 getConnection() 出错时关闭连接,它解决了问题
  • 好的,但您不需要在 getConnection() 中关闭连接。调用者肯定会调用 releaseConnection 方法,即使在获取连接时抛出异常。请仔细检查 releaseConnection 方法,它会让你关闭连接实例。
【解决方案2】:

关闭连接,万一出错解决了问题。

@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
  }

【讨论】:

    猜你喜欢
    • 2017-07-10
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 2022-07-24
    • 2017-03-25
    • 2011-01-19
    相关资源
    最近更新 更多