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

概述:

在這裏所謂的數據庫鏈接是指經過網絡協議與數據庫服務之間創建的TCP鏈接。一般,與數據庫服務進行通訊的網絡協議無需由應用程序自己實現。html

緣由有三:java

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

正由於如此,因此現實的實現方式是:mysql

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

其次,將實現這個標準協議的客戶端獨立爲一個通訊庫,這樣只須要在應用程序中使用這個通訊組件庫就能夠方便地實現與數據庫進行交互。github

一般,咱們將實現了網絡協議的通訊庫稱之爲數據庫驅動程序。固然,對於不一樣的編程語言,須要對應編寫相應的數據庫驅動實現。以與關係型數據庫通訊爲例,在Java中實現的驅動程序爲JDBC,Python中的驅動程序爲MySQLdb。sql

因爲經過TCP與數據庫創建網絡鏈接的代價很是高昂,並且耗時(TCP創建鏈接須要「三次握手」,斷開鏈接須要「四次握手」)。因此在實踐中一般不直接單獨使用鏈接進行數據庫操做,而是使用鏈接池的方式,這主要是處於如下兩方面的考慮:數據庫

  1. 應用程序自己須要更低的響應時間,若是每次數據庫操做都須要通過「創建鏈接->通訊(增刪改查)->斷開鏈接」這個過程,那麼勢必會致使響應延時的增長。
  2. 避免服務器資源被耗盡,隨着業務量的增大,對應的數據庫操做必然會隨之增長,若是對客戶端的鏈接數不加以控制,可能會致使數據庫服務器的CPU和內存資源被大量的網絡鏈接快速耗盡,這樣將致使服務不可用。

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

Druid服務器

概述:druid:阿里出品,淘寶和支付寶專用數據庫鏈接池,支持全部JDBC兼容的數據庫,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。網絡

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

主要特點:爲分析監控設計;快速的交互式查詢;高可用;可擴展;Druid是一個開源項目,源碼託管在github上。

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

依賴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

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

數據庫鏈接池C3P0框架是個很是優異的開源jar,高性能的管理着數據源,c3p0有兩種數據源管理方式,一種是經過程序變自己來進行管理,還有一種是經過容器管理,

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

依賴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

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

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

單線程,併發量低,性能很差,適用於小型系統。

依賴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();
}

 

 

 

@ 轉載至網絡

相關文章
相關標籤/搜索