【问题标题】:Creating a database connection pool创建数据库连接池
【发布时间】:2010-12-14 23:37:12
【问题描述】:

需要有关创建数据库连接池的信息(与数据库无关),以及它们的效率如何?它们可以提高性能的条件是什么。

如何显式创建?

【问题讨论】:

    标签: database connection connection-pooling


    【解决方案1】:

    Apache DBCP 的介绍页面总结得很好:

    为每个人创建一个新的连接 用户可能很耗时(通常 需要多秒的时钟 时间),以执行数据库 可能需要的交易 毫秒。每打开一个连接 用户可能是不可行的 公共托管的互联网应用程序 其中同时用户数 可以很大。因此, 开发人员经常希望分享一个 所有开放连接的“池” 应用程序的当前用户。 实际用户数 在任何给定时间执行请求 通常是很小的百分比 活跃用户总数,以及 在请求处理期间是唯一的 数据库连接的时间 必需的。应用程序本身记录 进入 DBMS,并处理任何用户 内部帐户问题。

    它们的效率如何?取决于实施。通常,我希望池在启动时或请求时实例化连接。第一个连接需要到数据库的真实连接,然后当您请求连接时,您将获得一个现有的池连接。因此,第一个连接请求将花费最多时间,之后您只是从集合中提取对象(非常快)。

    【讨论】:

    • 由于 Sachin 专门询问池可以在哪里解决性能问题,我要补充一点,它们通常只在客户端-服务器应用程序中有意义,在这种应用程序中,您的连接数少于用户数。特别是,它们在一个用户连接到数据库的胖客户端应用程序中没有意义。
    【解决方案2】:

    创建与数据库的连接是非常昂贵的操作。连接池是创建和缓存的数据库连接的实例。每当需要到数据库的新连接时,都会使用池中的一个,而不是创建新连接。 .NET + SQL Server 等一些平台默认使用连接池(您不需要创建自己的)。因此,它们基本上通过节省每次创建新连接的时间来提高性能。

    【讨论】:

      【解决方案3】:

      使用连接池可以节省每次访问的时间,因为连接已经建立。

      而且,至少在 Oracle 上,您将编译后的语句与连接保持联系,因此重复执行相同的 SQL 语句会更快。

      (如果您使用 Java/JDBC,请参阅 PreparedStatement)

      反性能的唯一风险是当您在池中保留太多空闲连接时,相关的资源(您端和数据库上)会被浪费。

      【讨论】:

      • 请记住,连接也会锁定服务器中的资源(线程、缓冲区)。并且已建立的连接始终通过特定的用户/密码对进行身份验证。因此,如果连接池仅起作用,则当所有连接都使用相同的数据库帐户时
      • 是的,您对唯一数据库帐户的关注完全正确。 (这在从 C/S 应用程序迁移到 Web 时可能会出现问题,例如,如果授权在 DB 中,则基于连接的用户。)
      【解决方案4】:

      创建数据库连接可能是一项昂贵的操作,也可能不是一项昂贵的操作,具体取决于您的环境以及您打算如何使用它。

      如果您要运行一个非常简单的查询,那么连接可能需要与查询一样长(或更长)的时间。

      某些数据库的连接开销比其他数据库大得多;如果调整正确,mysql 应该很少(超过建立 tcp 连接和进行协议握手的时间)。但是,如果您的服务器的延迟非常高,即使这也可能非常重要(特别是如果您打算只执行几个查询)。

      如果您打算执行 100 个查询,或者一些非常慢的查询,那么连接时间就会变得微不足道。

      通常我会说每次都打开一个新连接,直到您可以证明这是一个真正的性能问题。使用连接池可能会导致 BUGS,这是我们不喜欢的:

      • 在池中上次使用后连接状态未完全重置 - 因此某些状态会持续存在并产生导致错误的意外行为
      • 连接以某种方式关闭(可能是有状态的防火墙超时),无法检测到,因此应用尝试使用关闭的连接,导致长时间延迟或失败

      【讨论】:

      • 对于 Web 环境,您真的不希望在查询开始时获得连接(来自池或其他),执行 100 次查询,然后关闭它。这有效地锁定了您的连接(这是数据库端的有限资源),从而限制了您的网站可以支持的用户数量。最好从池中取出,使用,放回池中(在任何需要大量时间的代码之前)。考虑到支持连接池只需几行代码(一次只在您的数据源管理器实用程序类中),没有理由不使用它们。
      【解决方案5】:

      查看基准部分中的 BoneCP (http://jolbox.com) 中的一些数字。请记住,preparedStatements 等与连接相关联,因此如果您自己处理连接,则需要一次又一次地准备它们(连接池也会为您缓存这些)。

      到目前为止我最好的解决方案:使用一个lazyDataSource,它只在你真正需要它时给你一个连接(即不盲目 - 如果数据可以来自缓存,那么你可以避免数据库命中)

      【讨论】:

        【解决方案6】:

        你的问题有点含糊:

        你想homegrow一个连接池实现吗?如果是这样,这是一个很好的起点:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/conpool.html 但是这对于生产环境是非常不鼓励的。最好使用现有且经过全面测试的连接池 API,例如 DBCPC3P0

        或者您想知道如何使用连接池?如果是这样,答案取决于您使用的连接池 API。幸运的是,它通常可以在相关 API 的网站上找到。

        或者您想知道何时/为什么使用连接池?如果是这样,如果您有一个长期存在的应用程序(例如 web 应用程序)并且您需要经常连接数据库,它肯定会提高连接性能。正常的 JDBC 做法是:在 最短 可能的范围内(即在相同的方法块内)获取 .因为连接相当昂贵并且可能需要 200 毫秒甚至更多的时间,所以使用连接池要快得多。它按需提供连接并负责实际关闭连接。然而,这并不意味着你可以改变你编写 JDBC 的方式,你仍然需要在最可能的范围内获取和关闭它们。您唯一需要更改的是获取连接的方式。例如。从改变

        connection = driverManager.getConnection();
        

        connection = connectionPool.getConnection();
        

        只要您的 JDBC 代码写得好,就不需要再做任何更改。

        【讨论】:

          【解决方案7】:

          使用tomcat创建数据库连接池

          1. Tomcat进入资源里面:conf/context.xml

          将资源条目放在 context.xml 文件中:

          <!-- jdbc/jndiName jndi --> 
          <Resource name="jdbc/jndiName" auth="Container" type="javax.sql.DataSource" initialSize="1" maxActive="100" maxIdle="30" maxWait="10000" username="enter username" password="enter password" driverClassName="diver name" url="jdbc database url"/>
          

          2。创建一个将创建连接池的类

          public class MyConnectionFactory {
              private static String module = "[ QuoteConnectionFactory ]";
              private static QuoteConnectionFactory connectionFactory;
          
              protected QuoteConnectionFactory() {
              }
          
              /**
               *
               * @return=>getInstance() is a static method which will return the instance
               *                        of its own class
               */
              public static QuoteConnectionFactory getInstance() {
                  if (connectionFactory == null)
                      connectionFactory = new QuoteConnectionFactory();
                  return connectionFactory;
              }
          
              /**
               *
               * @param jndiName
          
               */
              public Connection getConnection(String jndiName) {
                  System.out.println("jndiName=======" + jndiName);
                  Connection conn = null;
                  InitialContext cxt = null;
                  DataSource dataSource = null;
                  try {
                      cxt = new InitialContext();
                      Context envContext  = (Context)cxt.lookup("java:/comp/env");
                      dataSource = (DataSource)envContext.lookup(jndiName);
                  } catch (NamingException e) {
          
                  } catch (Exception e) {
          
                  }
          
                  if (dataSource == null) {
          
                      try {
                          conn = dataSource.getConnection();
                      } catch (Exception e) {
          
                      }
          
                      System.out.println("connection===================" + conn);
                      return conn;
                  }
              }
          

          3.编辑 web.xml 文件

          <resource-ref>
              <description>DB Connection</description>
              <res-ref-name>jdbc/jndiName</res-ref-name>
              <res-type>javax.sql.DataSource</res-type>
              <res-auth>Container</res-auth>
          </resource-ref>
          

          4.在代码中使用

          Connection con= QuoteConnectionFactory.getInstance(). getConnection("jndiName");
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-26
            • 2010-10-23
            • 2014-04-09
            • 1970-01-01
            • 1970-01-01
            • 2015-08-09
            • 2012-08-03
            相关资源
            最近更新 更多