当前位置: 首页 > 知识库问答 >
问题:

从ConnectionPools获取和释放JDBC连接的频率?

范成周
2023-03-14

我正在重构一个最初设计于20世纪90年代中期的遗留系统。在那些日子里,JDBC连接是一种稀缺资源,没有可靠的连接池实现,因此连接被保持得尽可能长。这导致以下结构:

class ClientHandler {
  Connection conn=DriverManager.createConnection(...);
  Statement stmt=conn.createStatement();
  Statement stmt2=conn.createStatement();

  public ReplyType handleCommand(RequestType req) {
    if (req.requestType==RequestType.LOGIN)
      return new LoginManager(stmt,stmt2).login(req.requestData);
    ...
  }
}

class LoginManager {
  Statement stmt,stmt2;
  public LoginManager(Statement stmtx,Statement stmt2x) { stmt=stmtx; stmt2=stmt2x; }
  public login(RequestData data) {
    ResultSet rs=stmt.executeQuery("select count(*) from users where name="+data.getName()+" and pw="+data.getPassword());
    if (!rs.next()) throw new IllegalStateException();
    if (rs.getInt(1)==0)
      throw new WhateverException("error.wrongpassword");
  }
}

这只是一个例子来说明这种结构中的数据库连接

>

  • 提前打开

    会长期开放

    传递给所有必须访问数据库的人

    现在,在重构过程中,我想删除这种操作模式。考虑到连池和操作尽可能无状态,我可以想象删除数据库连接的每一次传递,并在我需要的时候简单地(从池中)获取一个数据库连接,然后将它们丢弃(返回池中),始终在相同的范围内。上面相同的代码可以像这样重写(Java7 try-with-资源样式):

    class ClientHandler {
    
      public ReplyType handleCommand(RequestType req) {
        if (req.requestType==RequestType.LOGIN)
          return new LoginManager().login(req.requestData);
        ...
      }
    }
    
    class LoginManager {
      public login(RequestData data) {
        try (Connection conn=StaticConnectionPoolBridge.createConnection) {
          ResultSet rs=conn.createStatement().executeQuery("select count(*) from users where name="+data.getName()+" and pw="+data.getPassword());
          if (!rs.next()) throw new IllegalStateException();
          if (rs.getInt(1)==0)
            throw new WhateverException("error.wrongpassword");
        }
      }
    }
    

    我的问题是:这样重构明智吗?我的意思是,连接池旨在使数据库连接创建成为轻量级操作。但它是否如此轻巧,以至于你可以以如此精细的方式获取和丢弃?或者我应该尝试将连接池的获取释放周期限制在一些不太大的数量,例如,通过将获取的连接和语句至少移动到一些(实用程序)方法?在这样的系统中使用连接池有什么经验法则吗?

    FWIW:整个系统的主干是Play 2.3,它在内部使用BoneCP连接池。当然,这个系统在数据库访问代码中具有一些抽象层,我在这里省略了这些抽象层,以使html" target="_blank">示例代码尽可能简单。

  • 共有2个答案

    慕意致
    2023-03-14

    我终于完成了前面提到的重构。实际上,我删除了几乎所有的语句传递,并用大量的资源尝试替换了它。我们的框架包含一些类似于LazyConnectionDataSourceProxy的内容,我添加了一个轻量级层,将连接绑定到线程,这样,如果同一个线程打开多个并行语句,所有语句都来自同一个连接。

    这种方式实际上提高了系统在某些工作负载下的速度,并且不会导致连接池引擎出现任何问题。所以,我想说这次重构是成功的,像BoneCP这样的连接池可以每秒处理数百个连接打开和关闭。

    甄鹏云
    2023-03-14

    从连接池中获取和释放连接是非常轻量级的,因为您最终要做的唯一事情就是将该连接重新放入队列中。在这些行动中你根本不会和DB说话。

     类似资料:
    • 我已经按照这里的示例中所述配置了TcpClient。我试图使以下代码在服务器意外关闭连接的情况下具有弹性: 在这种情况下,我希望方法“getConnectionFromPool”能够从池中检索连接,或者如果没有可用的连接,则打开一个新连接。 注意到后。connect()最终服从于ConnectionProvider。acquire(),我尝试使用tcpClient。connect(),但有必要更改

    • Tomcat在使用后不释放连接的原因可能是什么? 这是我的配置

    • 我有一个Hibernate和光数据源的Spring Boot项目。如果我使用注入的SessionFactory对象来获取会话对象,几天后,我会发现与数据库操作相关的任何方法都有这样的异常(只有重新启动才能解决这个问题): 似乎手动使用的会话使此问题。(我有类似的项目,具有相同的配置和功能,但没有注入SessionFactory和Session...我根本没有这样的问题) 应用程序. yaml: 数

    • 我们的项目中有Spring boot/Hibernate/MYSQL应用程序,并使用Hikari作为连接池。服务启动几分钟后,我们发现以下问题: org.springframework.web.util.嵌套异常:请求处理失败;嵌套异常org.springframework.dao.DataAccessResourceFailureExc0019:无法获取JDBC连接;嵌套异常org.hibern

    • 我通过动态创建具有以下属性的数据源来连接mysql数据库,它工作正常,但过了一段时间后,它一直给我错误“无法获取JDBC连接”。 它被托管在AWS和Tomcat环境中。DB是AWS的RDS。 更新: 原因: