问答中心谁给介绍一下JDBC连接池是啥?
xinran 提问于 3年 以前

我想了解JDBC连接池
为什么我们需要连接池?
连接池实际发生了什么?

1 个回答
zongmu 用户 回答于 3年 以前

连接池是一种创建和维护JDBC连接对象集合的机制。维护连接对象池的主要目标是利用可重用性。只有当没有可重用的连接对象时,才会创建一个新的连接对象。该技术可以提高应用程序的整体性能。本文将尝试显示如何将此池化机制应用于Java应用程序。
为什么我们需要连接池?
建立数据库连接是一个非常耗资源的过程,涉及很多开销。此外,在多线程环境中,打开和关闭连接可能会使情况恶化。要了解每个创建新数据库连接请求的实际情况,请考虑以下几点。数据库连接使用的是成立的DriverManager数据源对象。

  • 一个应用程序调用getConnection()方法。
  • JDBC驱动程序请求JVM套接字。
  • JVM必须确保该呼叫不违反安全性方面(根据applet的情况)。
  • 在进入网络云之前,调用可能必须通过防火墙渗透。
  • 在到达主机时,服务器处理连接请求。
  • 数据库服务器初始化连接对象并返回给JDBC客户端(再次,通过相同的过程)。
  • 最后,我们得到一个连接对象。

这只是对幕后实际情况的概述。放心,实际过程比这更复杂和精细。在单线程受控环境中,数据库事务通常是线性的,例如打开连接,执行数据库事务,以及在完成后关闭连接。现实应用更复杂; 连接池的机制可以增加性能,尽管还有许多其他属性对应用程序的整体性能至关重要。
当我们深入了解时,连接池的概念的复杂性变得更加糟糕。但是,感谢专门为连接池的原因制作图书馆的人们。这些库遵循JDBC的规范,并提供更简单的API,以便在Java应用程序中实际实现它们。
连接池实际发生了什么?
连接池在幕后工作,不影响应用程序的编码方式。这意味着一旦属性被设置,开发人员几乎可以忘记它,并专注于代码,就像任何其他JDBC应用程序一样。但是,应用程序必须使用DataSource对象来获取连接,而不是使用DriverManager类。但是,这并不意味着如果我们使用DataSource对象,则使用连接池。什么是数据源对象所做的就是以标准方式JNDI命名服务注册。例如:

Context context=new InitialContext();
DataSource dataSource=(DataSource)
 context.lookup("jdbc/library_jndi");

但是,当DataSource使用连接池时,查找将从可用的连接对象池中返回一个连接。如果没有可用的连接,查找将创建一个新的连接。应用程序建立与数据库的连接并以通常的方式访问数据。

Connection connection=dataSource.getConnection
 ("root","password");
// ...
connection.close();

一旦应用程序完成数据库活动,它将显式地关闭连接。这使得释放的连接可用于再次使用。池连接的关闭事件指示池模块恢复到连接池。由于连接对象的重用不需要任何代码更改,因此创建新连接的速度更快。
JDBC 3.0 API提供了连接池的一般框架。几个第三方供应商建立在这个框架上,实现自己的缓存或池化算法。一般的JDBC API框架以接口的形式提供了三个钩子,几个第三方供应商实现了它们的连接池库。他们是:

  • 的PooledConnection
  • ConnectionPooledDataSource
  • ConnectionEventListener

请参阅Java API文档,以了解这些接口的详细描述。我们不在这里详细介绍 而是让我们关注如何在Java应用程序中实现连接池机制。如前所述,有许多第三方库可用,如C3P0,UCP,BoneCP,H2,DBCP等等。这里,我们仅关注其中之一。
我们需要以下的例子
以下示例将是最小的独立Java应用程序。我们将使用的数据库是MySQL。所以我们需要

  • Eclipse IDE(可选)
  • MySQL JDBC驱动程序

我们将要处理的数据库表的DDL语句如下所示:

create table books
(
 isbn varchar(20) primary key,
 title varchar(50),
 edition varchar(20),
 price float(10,2)
);

连接到c3p0
c3p0是根据LGPL或EPL条款提供的第三方连接池库。该官方网站C3P0状态:
c3p0是一个易于使用的库,用于通过使用jdbc3规范和jdbc2的可选扩展定义的功能来增加传统JDBC驱动程序“企业级”。从版本0.9.5开始,c3p0完全支持jdbc4规范。
特别是,c3p0提供了几个有用的服务:

  • 一个类将传统的基于DriverManager的JDBC驱动程序适用于用于获取数据库连接的较新的javax.sql.DataSource方案。
  • DataSources背后的Connections和PreparedStatements的透明池化,可以围绕传统驱动程序或任意未解压的DataSource进行“包装”。

它的设计很简单,只需要两个jar文件:

  • c3p0.x.x.x.x.jar
  • mchange-commons-java-x.x.xjar

除了MySQL JDBC驱动程序,这些jar需要在CLASSPATH中。

package org.mano.example;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0DataSource {
   private static C3P0DataSource dataSource;
   private ComboPooledDataSource comboPooledDataSource;

   private C3P0DataSource() {
      try {
         comboPooledDataSource = new ComboPooledDataSource();
         comboPooledDataSource
            .setDriverClass("com.mysql.jdbc.Driver");
         comboPooledDataSource
            .setJdbcUrl("jdbc:mysql://localhost:3306/testdb");
         comboPooledDataSource.setUser("root");
         comboPooledDataSource.setPassword("secret");
      catch (PropertyVetoException ex1) {
         ex1.printStackTrace();
      }
   }

   public static C3P0DataSource getInstance() {
      if (dataSource == null)
         dataSource = new C3P0DataSource();
      return dataSource;
   }

   public Connection getConnection() {
      Connection con = null;
      try {
         con = comboPooledDataSource.getConnection();
      } catch (SQLException e) {
         e.printStackTrace();
      }
      return con;
   }
}

package org.mano.example;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class MainApp {

   public static void insertOrUpdate(String isbn, String title,
         String edition, float price) {
      try (Connection con = C3P0DataSource.getInstance()
            .getConnection()) {
         PreparedStatement pstmt=null;
         if(isIsbnExists(isbn)){
            pstmt = con.prepareStatement("UPDATE books "
                  + "SET title=?,edition=?,"
                  + "price=? WHERE isbn LIKE ?");
            pstmt.setString(1, title);
            pstmt.setString(2, edition);
            pstmt.setFloat(3, price);
            pstmt.setString(4, isbn);
         }else{
            pstmt = con.prepareStatement("INSERT INTO "
                  + "books(isbn,title,"
                  + "edition,price) VALUES (?,?,?,?)");
            pstmt.setString(1, isbn);
            pstmt.setString(2, title);
            pstmt.setString(3, edition);
            pstmt.setFloat(4, price);
         }
         pstmt.executeUpdate();
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }

  public static void isIsbnExists(String isbn) {
      Boolean flag = false;
      try (Connection con = C3P0DataSource.getInstance()
            .getConnection()) {
         Statement stmt=con.createStatement();
         ResultSet rs=stmt.executeQuery("SELECT isbn "
                     +"FROM books WHERE "
                     +"isbn LIKE '"+isbn+"'");
         flag=rs.next();
      } catch (SQLException e) {
         e.printStackTrace();
      }
      return flag;
   }

   public static void delete(String isbn) {
      try (Connection con = C3P0DataSource.getInstance()
            .getConnection()) {
         PreparedStatement pstmt=null;
         if(isIsbnExists(isbn)){
            pstmt = con.prepareStatement("DELETE FROM "
                  + "books "
                  + "WHERE isbn LIKE ?");
            pstmt.setString(1, isbn);
            pstmt.executeUpdate();
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }

   public static void showAll() {
      try (Connection con = C3P0DataSource.getInstance()
            .getConnection()) {
         Statement stmt = con.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM books");
         ResultSetMetaData metadata = rs.getMetaData();
         int cols = metadata.getColumnCount();
         System.out.println("\n-----------------------------"
         + "--------------------------------");
         for (int i = 0; i < cols; i++) {
            System.out.printf("%-20s\t",
            metadata.getColumnName(i + 1).toUpperCase());
         }
         System.out.println("\n-----------------------------"
         + "--------------------------------");
         while (rs.next()) {
            for (int i = 0; i < cols; i++)
            System.out.printf("%-20s\t", rs.getObject(i + 1));
            System.out.println();
         }
         System.out.println("-------------------------------"
         + "--------------------------------");

      catch (SQLException e) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      showAll();
      insertOrUpdate("111111", "Complex Numbers",
         "Second", 56.78f);
      showAll();
      insertOrUpdate("111111", "Complex Numbers",
         "Fourth", 87.50f);
      showAll();
      delete("111111");
      showAll();
   }
}

Output

----------------------------------------------------------------
ISBN             TITLE                   EDITION           PRICE
----------------------------------------------------------------
456789           Graph Theory            Second            33.8
567890           Set Theory              Fourth            34.89
----------------------------------------------------------------

----------------------------------------------------------------
ISBN             TITLE                   EDITION           PRICE
----------------------------------------------------------------
111111           Complex Numbers         Second            56.78
456789           Graph Theory            Second            33.8
567890           Set Theory              Fourth            34.89
----------------------------------------------------------------

----------------------------------------------------------------
ISBN             TITLE                   EDITION           PRICE
----------------------------------------------------------------
111111           Complex Numbers         Fourth            87.5
456789           Graph Theory            Second            33.8
567890           Set Theory              Fourth            34.89
----------------------------------------------------------------

----------------------------------------------------------------
ISBN             TITLE                  EDITION            PRICE
----------------------------------------------------------------
456789           Graph Theory           Second             33.8
567890           Set Theory             Fourth             34.89
----------------------------------------------------------------

结论
连接池特别适用于在连接请求被丢弃或延迟的高负载环境中优化性能。这种情况对应用程序的整体性能有不利影响。实际上,在创建JDBC Web或企业应用程序时,由于所有实际的原因,总是使用连接池。第三方图书馆非常稳定,能够提供他们声称的图书馆。了解连接池的概念并能够实现它们是所有JDBC程序员必须的。

回答问题需要您先 登录 或是 注册 登录!