创建数据库连接池

7
需要有关创建数据库连接池的信息(无论是哪种类型的数据库),以及它们的效率如何?在什么条件下可以提高性能?
如何显式地创建它?
7个回答

6

您的问题有点含糊:

您想自己编写一个连接池实现吗?如果是这样,这是一个不错的起点:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/conpool.html。但是,在生产环境中强烈不建议这样做。最好使用现有的经过充分测试的连接池API,例如DBCPC3P0

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

还是您想知道何时/为什么使用连接池?如果是这样,它肯定会提高连接性能,特别是当您拥有一个长寿的应用程序(例如Web应用程序)并且需要频繁连接数据库时。正常的JDBC实践是:在最短的范围内获取并关闭 ConnectionStatementResultSet(即在同一方法块内)。由于连接相当昂贵,可能需要花费高达200ms或更长时间,因此使用连接池要快得多。它按需提供连接并负责实际关闭连接。但这并不意味着您可以更改编写JDBC的方式,仍然需要在最短的范围内获取并关闭它们。您唯一需要更改的是获取连接的方式。例如,从以下方式进行更改:

connection = driverManager.getConnection();

为了

connection = connectionPool.getConnection();

只要您的JDBC代码编写得好,就不需要进行更改。

3

Apache DBCP的介绍页面对此进行了简要总结:

为每个用户创建一个新连接可能非常耗时(通常需要多秒钟的时间),而这只是为执行可能只需要毫秒级时间完成的数据库事务。在公共托管的Internet应用程序中,打开每个用户的连接可能是不可行的,因为同时在线的用户数量可能非常大。因此,开发人员通常希望在所有当前应用程序用户之间共享一组已打开的连接池。“实际上,在任何给定时间执行请求的用户数量通常只占活动用户总数的很小比例,并且在请求处理期间是唯一需要数据库连接的时间。应用程序本身登录到DBMS,并在内部处理任何用户账户问题。”

它们有多有效?这取决于具体实现方式。通常我希望池在启动时或按需实例化连接。第一个连接将需要一个真正的连接到数据库,然后当您请求连接时,您将获得一个现有的池连接。因此,第一个连接请求将花费最长时间,之后您只需从集合中检索对象(非常快速)。


1
由于Sachin特别询问了池可以解决性能问题的地方,我想补充一下,它们通常只在客户端-服务器应用程序中有意义,在这种应用程序中,您拥有的连接数少于用户数。特别是在一个厚客户端应用程序中,其中一个用户连接到数据库,它们将没有意义。 - John Stauffer

1

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


1

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

此外,至少在Oracle上,您可以将编译的语句链接到连接,因此重复执行相同的SQL语句会更快。

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

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


请记住,连接也会锁定服务器中的资源(线程、缓冲区)。而且,已建立的连接始终通过特定的用户/密码对进行身份验证。因此,如果连接池仅在所有连接使用相同的数据库帐户时才起作用。 - Carsten Kuckuk
是的,你完全正确,唯一数据库账户的问题确实存在。例如,在从C/S应用程序迁移到Web时,如果授权在数据库中基于连接的用户,则可能会出现问题。 - Pierre Sevrain

1

看看BoneCP(http://jolbox.com)中的基准测试部分,了解一些数字。请记住,预处理语句等与连接绑定,因此如果您自己处理连接,则需要反复准备它们(连接池也会为您缓存它们)。

我迄今为止最好的解决方案:使用lazyDataSource,仅在真正需要时提供连接(即不盲目地 - 如果数据可以来自缓存,则可以避免数据库命中)


1

使用Tomcat创建数据库连接池

1. 在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;
        }
    }

编辑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>

使用于编码中。
Connection con= QuoteConnectionFactory.getInstance(). getConnection("jndiName");

0

创建数据库连接可能是一个昂贵的操作,这取决于您的环境和您打算使用它做什么。

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

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

如果您计划执行 100 个查询或几个非常慢的查询,则连接时间会消失得无影无踪。

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

  • 在池中上一次使用后,连接状态没有完全重置-因此某些状态会残留并创建意外行为,从而导致错误
  • 连接以某种方式关闭(可能是由于有状态防火墙超时),无法检测到,因此应用程序尝试使用已关闭的连接,导致长时间延迟或失败

对于 Web 环境而言,你真的不想在查询开始时获取一个连接(从池中或其他方式),执行上百个查询,然后关闭它。这实际上会锁定你的连接(数据库端的有限资源),从而限制了网站所能支持的用户数量。最好的做法是从池中取出、使用,并在任何需要较长时间的代码之前放回池中。考虑到支持连接池只需几行代码(仅在数据源管理器实用程序类中),没有理由不使用它们。 - JeeBee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接