數據庫連接池 - (druid、c3p0、dbcp)


一、概述

在這里所謂的數據庫連接是指通過網絡協議與數據庫服務之間建立的TCP連接。通常,與數據庫服務進行通信的網絡協議無需由應用程序本身實現。

原因有三:

  1. 實現復雜度大,需要充分理解和掌握相應的通信協議。
  2. 代碼難以復用,每個應用程序都需要獨立實現一套對應的網絡協議(不同公司之間,同一公司的不同技術棧之間難以復用實現相同協議的代碼)
  3. 性能難以保證,不同的網絡協議實現可能存在巨大的性能差距。

正因為如此,所以現實的實現方式是:

首先,定義網絡協議標准,這樣只要支持這個標准協議的數據庫就可以使用相應的客戶端與之通信。

其次,將實現這個標准協議的客戶端獨立為一個通信庫,這樣只需要在應用程序中使用這個通信組件庫就可以方便地實現與數據庫進行交互。

通常,我們將實現了網絡協議的通信庫稱之為數據庫驅動程序。當然,對於不同的編程語言,需要對應編寫相應的數據庫驅動實現。以與關系型數據庫通信為例,在Java中實現的驅動程序為JDBC,Python中的驅動程序為MySQLdb。

由於通過TCP與數據庫建立網絡連接的代價非常高昂,而且耗時(TCP建立連接需要“三次握手”,斷開連接需要“四次握手”)。所以在實踐中通常不直接單獨使用連接進行數據庫操作,而是使用連接池的方式,這主要是處於以下兩方面的考慮:

  1. 應用程序本身需要更低的響應時間,如果每次數據庫操作都需要經過“建立連接->通信(增刪改查)->斷開連接”這個過程,那么勢必會導致響應延時的增加。
  2. 避免服務器資源被耗盡,隨着業務量的增大,對應的數據庫操作必然會隨之增加,如果對客戶端的連接數不加以控制,可能會導致數據庫服務器的CPU和內存資源被大量的網絡連接快速耗盡,這樣將導致服務不可用。

在Java中使用得比較流行的數據庫連接池主要有:DBCP,c3p0,druid。
另外,不論使用什么連接池,低層都是使用JDBC連接,即:在應用程序中都需要加載JDBC驅動程序。

二、Druid

1)概述

druid 阿里出品,淘寶和支付寶專用數據庫連接池,支持所有JDBC兼容的數據庫,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。

Druid是Java語言中最好的數據庫連接池,Druid能夠提供強大的監控和擴展功能,是一個可用於大數據實時查詢和分析的高容錯、高性能的開源分布式系統,尤其是當發生代碼部署、機器故障以及其他產品系統遇到宕機等情況時,Druid仍能夠保持100%正常運行。

2)主要特色

為分析監控設計;快速的交互式查詢;高可用;可擴展;Druid是一個開源項目,源碼托管在github上。

Druid針對Oracle和MySql做了特別優化。

3)代碼演示

依賴Jar包:不分版本號

druid-1.1.5.jar

mysql-connector-java-8.0.14.jar

DruidDataSource dataSource = new DruidDataSource();
//獲取驅動
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
//建立連接
dataSource.setUrl("jdbc:mysql://localhost:3306/class38?serverTimezone=Asia/Shanghai");
dataSource.setUsername("root");
dataSource.setPassword("123456");
try {
    //獲取連接
    DruidPooledConnection conn = dataSource.getConnection();
    PreparedStatement statement = conn.prepareStatement("insert into student values(?,?,?,?)");
    statement.setInt(1, 13);
    statement.setString(2, "小明");
    statement.setString(3, "數據庫");
    statement.setInt(4, 150);
    int i = statement.executeUpdate();
    System.out.println(i);
} catch (SQLException e) {
    e.printStackTrace();
}

設置配置文件druid.properties

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/class38?serverTimezone=Asia/Shanghai
username = root
password = 123456

通過配置文件實現連接

//建立工廠
DruidDataSourceFactory factory = new DruidDataSourceFactory();
Properties p = new Properties();
InputStream in = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
try {
    //讀取配置文件中的信息
    p.load(in);
    DataSource dataSource = factory.createDataSource(p);
    Connection conn = dataSource.getConnection();
    PreparedStatement statement = conn.prepareStatement("select * from student");
    ResultSet result = statement.executeQuery();
    while(result.next()){
        System.out.println(result.getInt(1)+","+result.getString(2)+","+result.getString(3)+","+result.getInt(4));
    }
} catch (Exception e) {
    e.printStackTrace();
}

三、C3P0

1)概述

開源的JDBC連接池,實現了數據源和JNDI綁定,支持JDBC3規范和JDBC2的標准擴展。目前使用它的開源項目有Hibernate、Spring等。

數據庫連接池C3P0框架是個非常優異的開源jar,高性能的管理着數據源,c3p0有兩種數據源管理方式,一種是通過程序變本身來進行管理,還有一種是通過容器管理,

c3p0有自動回收空閑連接功能。單線程,性能較差,適用於小型系統,代碼600KB左右。

2)代碼演示

依賴Jar包:不分版本號

mysql-connector-java-8.0.14.jar

c3p0-0.9.5.2.jar

mchange-commons-java-0.2.11.jar

連接使用C3P0

1.1 - 使用Java API方式配置c3p0

ComboPooledDataSource dataSource = new ComboPooledDataSource();
    try {
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/class38?serverTimezone=Asia/Shanghai");
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        Connection conn = dataSource.getConnection();
        PreparedStatement statement = conn.prepareStatement("delete from student where id=?");
        statement.setInt(1, 11);
        int i = statement.executeUpdate();
        System.out.println(i);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

1.2 - 直接在連接池中獲取連接

DataSource ds = new ComboPooledDataSource();/
try {
    Connection connection = ds.getConnection();
    String sql = "select * from goods";
    PreparedStatement prepareStatement = connection.prepareStatement(sql);// 設置sql語句
    ResultSet executeQuery = prepareStatement.executeQuery();// 運行
    while (executeQuery.next()) {
        System.out.println("商品:" + executeQuery.getObject(2).toString());
    }
    executeQuery.close();
    prepareStatement.close();
    connection.close();
} catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

1.3 - 使用DBUtils工具連接:需要配置XML數據源,使用工具連接不需要close

//獲取數據源,讀取的是C3P0-config默認配置創建數據庫連接池對象
DataSource ds = new ComboPooledDataSource();
//創建QueryRunner帶參對象
QueryRunner queryRunner = new QueryRunner(ds);
//SQL UPDATE語句
String sql = "DELETE FROM type WHERE id in(?,?)";
//執行UPDATE語句,返回一個int類型的結果
int update = queryRunner.update(sql,6,7);
System.out.println(update);

② 使用c3p0.properties文件進行配置

數據源配置:c3p0.properties

需要在classpath路徑下添加配置文件:c3p0.properties,內容如下:

c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://host:port/db
c3p0.user=root
c3p0.password=
c3p0.minPoolSize=5
c3p0.maxPoolSize=20
c3p0.acquireIncrement=5

在應用程序中只需要直接創建ComboPooledDataSource對象即可(c3p0會自動從classpath加載c3p0.properties中的配置信息):

ComboPooledDataSource cpds = new ComboPooledDataSource();
Connection conn = cpds.getConnection();
query(conn);
cpds.close();

注意 使用c3p0.properties作為配置文件時,每個參數的name前綴必須是“c3p0”,如:“c3p0.driverClass=com.mysql.jdbc.Driver”

使用c3p0-config.xml文件進行配置

數據源配置:c3p0-config.xml

使用這種方式會比使用c3p0.properties更加高級,支持配置多個數據源,同樣需要在classpath路徑下添加文件:c3p0-config.xml

<c3p0-config>
    <!-- 這是默認配置信息 -->
    <default-config>
        <!-- 連接四大參數配置 -->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl"><!--CDATA里面的特殊符號都當字符串處理-->
            <![CDATA[jdbc:mysql://localhost:3306/cakeshop?useUnicode=true&character=UTF-8&serverTimezone=GMT%2B8&useSSL=true]]>
        </property>
        <property name="user">用戶名</property>
        <property name="password">密碼</property>
        <!-- 池參數配置 -->
        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
    </default-config>
</c3p0-config>

 在應用程序中只需要直接創建ComboPooledDataSource對象即可(c3p0會自動從classpath加載c3p0-config.xml中的配置信息):

// 使用默認數據源
// ComboPooledDataSource cpds = new ComboPooledDataSource();

// 使用指定名稱的數據源
ComboPooledDataSource cpds = new ComboPooledDataSource("myDataSource");
Connection conn = cpds.getConnection();
query(conn);
cpds.close();

四、DBCP

1)概述

由Apache開發的一個Java數據庫連接池項目, Jakarta commons-pool對象池機制,Tomcat使用的連接池組件就是DBCP。

單獨使用dbcp需要3個包,預先將數據庫連接放在內存中,應用程序需要建立數據庫連接時直接到連接池中申請一個就行,用完再放回。

單線程,並發量低,性能不好,適用於小型系統。

2)代碼演示

依賴Jar包:不分版本號

mysql-connector-java-8.0.14.jar

commons-dbcp2-2.4.0.jar

commons-pool2-2.6.2.jar

commons-logging-1.2.jar

//創建連接池對象
BasicDataSource dataSource = new BasicDataSource();
//設置參數
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/class38?serverTimezone=Asia/Shanghai");
dataSource.setUsername("root");
dataSource.setPassword("123456");
try {
    //獲取連接對象
    Connection conn = dataSource.getConnection();
    //生成預編譯Statement對象
    PreparedStatement statement = conn.prepareStatement("insert into student values(null,?,?,?)");
    statement.setString(1, "帥帥");
    statement.setString(2, "大數據");
    statement.setInt(3, 100);
    //執行sql語句
    int i = statement.executeUpdate();
    System.out.println(i);
} catch (Exception e) {
    e.printStackTrace();
}

配置文件內容dbcp.properties

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/class38?serverTimezone=Asia/Shanghai
username = root
password = 123456

通過Properties配置文件連接

BasicDataSourceFactory factory = new BasicDataSourceFactory();
Properties p = new Properties();
try {
    InputStream in = DBCPDemo.class.getClassLoader().getResourceAsStream("dbcp.properties");
    //加載配置文件
    p.load(in);
    //創建一個對象並返回
    DataSource dataSource = factory.createDataSource(p);
    Connection conn = dataSource.getConnection();
    PreparedStatement statement = conn.prepareStatement("select * from student");
    ResultSet result = statement.executeQuery();
    while(result.next()){
        System.out.println(result.getInt(1)+","+result.getString(2)+","+result.getString(3)+","+result.getInt(4));
    }
} catch (Exception e) {
    e.printStackTrace();
}

@ 轉載至網絡


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM