1. 程式人生 > >資料庫連線池詳解與程式碼實現

資料庫連線池詳解與程式碼實現

一、資料庫連線池概念

       資料庫連線池:負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效能

二、背景

       資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現得尤為突出。對資料庫連線的管理能顯著影響到整個應用程式的伸縮性和健壯性,影響到程式的效能指標。資料庫連線池正是針對這個問題提出來的。

三、影響因素

        資料庫連線池在初始化時將建立一定數量的資料庫連線放到連線池中,這些資料庫連線的數量是由最小資料庫連線數制約。無論這些資料庫連線是否被使用,連線池都將一直保證至少擁有這麼多的連線數量。連線池的最大資料庫連線數量限定了這個連線池能佔有的

最大連線數,當應用程式向連線池請求的連線數超過最大連線數量時,這些請求將被加入到等待佇列中。資料庫連線池的最小連線數和最大連線數的設定要考慮到下列幾個因素:

1. 最小連線數

        是連線池一直保持的資料庫連線,所以如果應用程式對資料庫連線的使用量不大,將會有大量的資料庫連線資源被浪費。

2. 最大連線數

        是連線池能申請的最大連線數,如果資料庫連線請求超過此數,後面的資料庫連線請求將被加入到等待佇列中,這會影響之後的資料庫操作。

3. 最小連線數與最大連線數差距

        最小連線數與最大連線數相差太大,那麼最先的連線請求將會獲利,之後超過最小連線數量的連線請求等價於建立一個新的資料庫連線。不過,這些大於最小連線數的資料庫連線在使用完不會馬上被釋放,它將被放到連線池中等待重複使用或是空閒超時後被釋放。

四、原理

        連線池基本的思想是在系統初始化的時候,將資料庫連線作為物件儲存在記憶體中,當用戶需要訪問資料庫時,並非建立一個新的連線,而是從連線池中取出一個已建立的空閒連線物件。使用完畢後,使用者也並非將連線關閉,而是將連線放回連線池中,以供下一個請求訪問使用。而連線的建立、斷開都由連線池自身來管理。同時,還可以通過設定連線池的引數來控制連線池中的初始連線數、連線的上下限數以及每個連線的最大使用次數、最大空閒時間等等。也可以通過其自身的管理機制來監視資料庫連線的數量、使用情況等。

五、實現

一般來說,Java應用程式訪問資料庫的過程:
1、裝載資料庫驅動程式;
2、通過jdbc建立資料庫連線;
3、訪問資料庫,執行sql語句;
4、關閉資料庫連線。

編寫連線池需實現java.sql.DataSource介面。DataSource介面中定義了兩個過載的getConnection方法:

· Connection getConnection()

· Connection getConnection(String username, String password)

實現DataSource介面,並實現連線池功能的步驟:

1. 在DataSource建構函式中批量建立與資料庫的連線,並把建立的連線加入LinkedList物件中。

2. 實現getConnection方法,讓getConnection方法每次呼叫時,從LinkedList中取一個Connection返回給使用者。

3. 當用戶使用完Connection,呼叫Connection.close()方法時,Collection物件應保證將自己返回到LinkedList中,而不要把conn還給資料庫。Collection保證將自己返回到LinkedList中是此處程式設計的難點。

6、程式碼實現

package com.example.jdbcConnection;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Liuxd on 2018/8/19.
 */
public class TestC3p0 {

    private static Connection conn;
    private static ComboPooledDataSource dataSource;

    static {
        try {
            //獲得c3p0連線池物件
            dataSource = new ComboPooledDataSource();

            dataSource.setUser("root");
            dataSource.setPassword("root");
            dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/foo?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=false");
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            dataSource.setInitialPoolSize(2);//初始化池大小
            dataSource.setMaxIdleTime(30);//最大空閒時間
            dataSource.setMaxPoolSize(20);//最多連線數
            dataSource.setMinPoolSize(2);//最少連線數
            dataSource.setMaxStatements(50);//每次最多可以執行多少個批處理語句

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


    /**
     * 查詢
     */
    private static List<Object[]> query() {

        List<Object[]> list = new ArrayList<Object[]>();
        try {

            // 獲取資料庫連線
            conn = dataSource.getConnection();
            // 查詢sql
            String sql = "select * from user";


            // 讀取資料
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            //結果集
            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                int uid = resultSet.getInt("uid");
                String name = resultSet.getString("name");
                Integer age = resultSet.getInt("age");
                String phone = resultSet.getString("phone");
                String passwd = resultSet.getString("passwd");

                Object[] objects = new Object[]{uid, name, age, phone, passwd};

                list.add(objects);
            }

            resultSet.close();
            preparedStatement.close();
            //Connection連線物件歸還資料庫連線池
            conn.close();

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

        return list;
    }


    /**
     * 新增
     */
    private static void add(String name, int age, String phone, String passwd) {

        try {

            // 獲取資料庫連線
            conn = dataSource.getConnection();

            String insertSql = "insert into `user` (`name`, `age`, `phone`, `passwd`) values(?,?,?,?)";

            PreparedStatement ps = conn.prepareStatement(insertSql);
            ps.setString(1, name);
            ps.setInt(2, age);
            ps.setString(3, phone);
            ps.setString(4, passwd);
            int row = ps.executeUpdate();

            System.out.println("新增結果: " + row);


            ps.close();
            //Connection連線物件歸還資料庫連線池
            conn.close();

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

    }

    /**
     * 修改
     */
    private static void update(int uid, String name, int age, String phone, String passwd) {

        try {

            // 獲取資料庫連線
            conn = dataSource.getConnection();

            String updateSql = "UPDATE USER t SET t.name=? ,t.age=?,t.phone=?,t.passwd=? WHERE t.uid=?";

            PreparedStatement preparedStatement = conn.prepareStatement(updateSql);
            preparedStatement.setString(1, name);
            preparedStatement.setInt(2, age);
            preparedStatement.setString(3, phone);
            preparedStatement.setString(4, passwd);
            preparedStatement.setLong(5, uid);
//          執行sql
            preparedStatement.executeUpdate();

            int row = preparedStatement.executeUpdate();

            System.out.println("修改結果: " + row);

            //Connection連線物件歸還資料庫連線池
            conn.close();
            preparedStatement.close();

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

    }


    /**
     * 刪除
     */
    private static void deleteById(int uid) {

        try {

            // 獲取資料庫連線
            conn = dataSource.getConnection();

            String sql = "delete from USER where uid=?";

            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            preparedStatement.setInt(1, uid);

            int row = preparedStatement.executeUpdate();

            System.out.println("刪除結果: " + row);

            preparedStatement.close();
            //Connection連線物件歸還資料庫連線池
            conn.close();

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

    }


    public static void main(String[] args) {
        /**
         * 1、驗證連線數
         */
        for (int i = 0; i < 10; i++) {
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
                System.out.println(connection.toString());
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                if (null != connection) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }

        }

        /**
         * 2、查詢
         */
        List<Object[]> list = query();

        if (null != list && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                Object[] objects = list.get(i);
                for (int j = 0; j < objects.length; j++) {
                    System.out.print(objects[j] + "    ");
                }
                System.out.println();
            }
        }

        /**
         * 3、新增
         */
        String name = "樂樂";
        int age = 17;
        String phone = "13800138001";
        String passwd = "admin123";
        add(name, age, phone, passwd);

        /**
         * 4、修改
         */
        update(12, name, age, phone, passwd);

        /**
         * 5、刪除
         */
        deleteById(3);

    }

}

7、資料庫指令碼

create table `user` (
	`uid` bigint (20),
	`name` varchar (75),
	`age` int (3),
	`phone` varchar (360),
	`passwd` varchar (36)
); 
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('1','張倫','12','13800138001','admin');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('4','李威','12','23','admin');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('5','莉莉','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('6','小寶','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('7','李金剛','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('8','李金剛','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('9','菲菲','6','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('10','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('11','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('12','樂樂','17','13800138001','admin123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('13','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('14','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('15','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('16','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('17','李賽','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('18','樂樂','17','13800138001','admin123');

參考:

相關推薦

資料庫連線程式碼實現

一、資料庫連線池概念        資料庫連線池:負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效

stl map底層之紅黑樹插入步驟程式碼實現

本篇文章並沒有詳細的講解紅黑樹各方面的知識,只是以圖形的方式對紅黑樹插入節點需要進行調整的過程進行的解釋。 最近在看stl原始碼剖析,看到map底層紅黑樹的實現。為了加深對於紅黑樹的理解就自己動手寫了紅黑樹插入的實現。關於紅黑樹插入節點後破壞紅黑樹性質的幾種情況,可以在網

漢諾塔(必須經過中間柱子)遞迴非遞迴程式碼實現

首先介紹一下漢諾塔最初始的規則: 有三根相鄰的柱子,標號為A,B,C,A柱子從上到下按照金字塔狀疊放著n個不同大小的圓盤,現在把所有的盤子一個一個移動到柱子B上,並且每次移動同一根柱子上都不能出現大盤子在小盤子上方。 這是最初始的規則,實現的思路可以分為

『資料結構演算法』棧:程式碼實現

> 微信搜尋:碼農StayUp > 主頁地址:[https://gozhuyinglong.github.io](https://gozhuyinglong.github.io/) > 原始碼分享:[https://github.com/gozhuyinglong/blog-demos](h

資料庫連線的原理實現()

資料庫連線池類的設計 類1:資料庫連線池類DBconnctionPool 屬性: inuserd 當前正在使用的連線數(int 型別) maxConn 最大的連線數(int 型別) minConn 最小的連線數(int 型別) poolName 連線池的名稱(String 型別) ArrayList free

連線,c3p0dbcp的區別!

連線池:    連線池是建立和管理一個連線的緩衝池的技術,這些連線準備好被任何需要它們的執行緒使用。這項技術能明顯提高對資料庫操作的效能。  連線池的好處:(1)對於大多數應用程式,當它們正在處理事務時,僅需要能夠訪問JDBC連線的 1 個執行緒。當不處理事務時,這個連線就會

淺析資料庫連線原理分析實現

1 動機在專案初期對於資料庫的使用就是開啟一個連線並進行使用,使用過後關閉連線釋放資源,並且在後臺簡單測試中,並沒有出現問題。但是在與前端對接之後,發現頻繁地開啟和關閉連線會對效能造成很大的影響,而且之前假設的情況是接受的請求都是同步的,但是前端可能傳送非同步請求,當兩個請求

spring學習筆記(17)資料庫配置[1]spring資料連線

資料連線池 在spring中,常使用資料庫連線池來完成對資料庫的連線配置,類似於執行緒池的定義,資料庫連線池就是維護有一定數量資料庫連線的一個緩衝池,一方面,能夠即取即用,免去初始化的時間,另一方面,用完的資料連線會歸還到連線池中,這樣就免去了不必要的連線建立

Java——Web開發之開源的資料庫連線(C3P0DBCP)的使用

緊接上一篇資料庫連線池的學習,點連線直達~   資料庫連線池的簡單理解與使用 資料庫連線池DBCP程式碼連線與配置檔案: 1.先匯入使用的jar檔案,分別是dbcp.jar與pool.jar檔案 2.分別使用兩種方式實現,使用配置檔案(dbcpconfig.

httpclient架構原理介紹 & 連線

本篇重點介紹httpclient連線池的相關原理以及介紹,順帶的介紹httpclient傳送請求時的簡單介紹,並會帶上一些原始碼分析。本篇博文是基於httpclient的4.5.2版本進行介紹的。 一、傳送請求的流程原理 幾個關鍵的類和介面介紹 在

基於JDBC的資料庫連線技術研究應用

       近年來,隨著Internet/Intranet建網技術的飛速發展和在世界範圍內的迅速普及,計算機 應用程式已從傳統的桌面應用轉到Web應用。基於B/S(Browser/Server)架構的3層開發模式逐漸取代C/S(Client/Server)架構的開發模式,成為開發企業級應用和電子商務普遍採用

線索二叉樹以及程式碼實現

參照《大話資料結構》188到194頁。 一、二叉樹的線索儲存結構定義 /* 二叉樹線索儲存結構定義 Link = 0,代表指向左右孩子的指標 Thread= 1 代表指向前驅或後繼的線索*/ typedef enum{ Link, Thread} Pointe

資料庫連線 單例模式的實現

Java應用程式訪問資料庫的基本原理   在Java語言中,JDBC(Java DataBase Connection)是應用程式與資料庫溝通的橋樑,   即Java語言通過JDBC技術訪問資料庫。JDBC是一種“開放”的方案,它為資料庫應用開發人員﹑資料庫前臺工具開

資料庫連線的作用基本原理

1. 基本原理:在內部物件池中,維護一定數量的資料庫連線,並對外暴露資料庫連線的獲取和返回方法。 如外部使用者可通過getConnection方法獲取資料庫連線,使用完畢後再通過releaseConnection方法將連線返回,注意此時的連線並沒有關閉,而是由連線池管理器回

【內部排序】八:歸併排序(Merge Sort)程式碼

歸併排序是多次將兩個或兩個以上的有序表合併成一個新的有序表。最簡單的歸併是直接將兩個有序的子表合併成一個有序的表。   2-路歸併排序 在內部排序中,通常採用的是2-路歸併排序。即:將含有n個元素的序

Java連線

http://www.javaweb1024.com/java/JavaWebzhongji/2015/06/01/736.html 對於共享資源,有一個很著名的設計模式:資源池(Resource Pool)。該模式正是為了解決資源的頻繁分配﹑釋放所造成的問題。

TensorFlow實現Batch Normalization程式碼實現

為什麼我們要進行標準化? 具有統一規格的資料更方便神經網路學習到資料的規律。 舉個非常簡單的例子。假設我們的啟用函式是f(x)=tanh,輸入資料x從-10到10。如下圖所示: 加上標準化工序後,x被調整到[-1,1],那麼with和without標準化工序的資料輸

資料庫連線的理解使用

官方:資料庫連線池(Connection pooling)是程式啟動時建立足夠的資料庫連線,並將這些連線組成一個連線池,由程式動態地對池中的連線進行申請,使用,釋放。個人理解:建立資料庫連線是一個很耗時的操作,也容易對資料庫造成安全隱患。所以,在程式初始化的時候,集中建立多個數據庫連線,並把他們集中管理,

理解資料庫連線底層之手寫實現

前言 資料庫連線池的基本思想是:為資料庫連線建立一個“緩衝池”,預先在池中放入一定數量的資料庫連線管道,需要時,從池子中取出管道進行使用,操作完畢後,在將管道放入池子中,從而避免了頻繁的向資料庫申請資源,釋放資源帶來的效能損耗。在如今的分散式系統當中,系統的QPS瓶頸往往就

MS SQL Server 資料庫連線字串

問題 : 超時時間已到。在從池中獲取連線之前超時時間已過。出現這種情況可能是因為所有池連線都已被使用並已達到最大池大小。 解決辦法  1. 在程式碼裡面 , 把未關閉的連線關閉  2. 擴大共享池 , 方法如下 :解決方法可以是修改連線池的連線生存期 , 因為預設值是 6