(重點)MySQL(入門篇24)自制數據庫連接池(DateSource數據源)

數據庫連接池和線程池類似,主要是,Connection 相當浪費時間和內存(比新建線程慢多了)

在這裏插入圖片描述

一、連接池的背景

1. jdbc的背景

(1)成立背景:每個數據庫廠商都有自己的數據庫驅動,爲了實現我們可以方便地連接到到不同數據庫,(比如你的賬戶信息在MySQL數據庫,頭像圖片在Oracle數據庫),
(2)jdbc定義:jdbc是一個接口規範,數據庫驅動(Driver)由數據庫廠商自己來完成。關係如圖所示。
在這裏插入圖片描述
(3)回顧連接的步驟:啓動Driver,連接獲得connection,獲取statement,使用statement,增刪改,或者查詢(獲得resultSet)

2. jdbc鏈接池的概念:

**類似線程池:**一個容器,程序加載就自動生成幾個Connection ,然後用的時候比較方便,而且用完了不是關閉Connection,而是歸還。

3.爲什麼要使用連接池?

(1)連接數據庫的Connection十分浪費資源,(比如獲得connection連接需要 900 毫秒,獲得statement只需30毫秒,獲得 ResultSet只需要 3毫秒,)
(2)數據池技術:準備一些一些預先的資源,過來就連接準備好的預先的資源。
(3)增加同時執行SQL的數量:,你最高的statement總數爲 (最高負載):Connection數 * 每個Connection產生的statement數

二、連接池的實現(不用框架)

1.myJdbcPool.java實現步驟

1.在static批量生產配置的Connection放到Victor裏面(Victor線程安全)
2.在getConnection()方法裏,

  • 1.在集合victors取出一個Connection,
  • 2.並使用動態代理技術修改close()方法,讓其變成歸還connection對象到集合裏。

2.myJdbcPool.java 代碼


import javax.sql.DataSource;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Logger;

/**
 * JdbcPool 數據池(數據源)
 * #### 一.myJdbcPool.java實現步驟
 * 1.在loadConfiguration()批量生產配置的Connection放到Victor裏面(Victor線程安全)
 * 2.在getConnection()方法裏,
 * * (1).在集合victors取出一個Connection,
 * *  (2).並使用[動態代理技術]()修改close()方法,讓其變成歸還connection對象到集合裏。
 */
public class JdbcPool implements DataSource {
    public static Vector<Connection> victors = new Vector<>();

    /**
     * 1.在loadConfiguration()批量生產配置的Connection
     * 放到Victor裏面(Victor線程安全)
     */
    private static void loadConfiguration() {
        try {
            String configPath = "jdbcPoolConf.properties";
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(configPath));
            Properties properties = new Properties();

            //將輸入流的數據載入到Properties對象裏,inputSteam都可以?
            properties.load(bufferedInputStream);
            //用properties對象獲得配置文件的信息
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            int jdbcPoolInitSize = Integer.parseInt(properties.getProperty("jdbcPoolInitSize"));
            //驅動
            Class.forName(properties.getProperty("driver"));
            //如果沒有初始化就初始化,
            if (victors.size() == 0){
                for (int i = 0; i < jdbcPoolInitSize; i++) {
                    Connection connection = DriverManager.getConnection(url,user,password);
                    System.out.println("日誌--獲取到鏈接:"+configPath);
                    victors.addElement(connection);
                }
            }
        } catch (Exception e) {
            System.out.println("日誌--創建失敗!");
            e.printStackTrace();
        }

    }

    /**
     *  * 2.在getConnection()方法裏,
     *   (1).在集合victors取出一個Connection,
     *    (2).並使用[動態代理技術]()修改close()方法,
     *  讓其變成歸還connection對象到集合裏。
     * @return Connection,close()被動態代理修改了
     *
     */
    @Override
    public  Connection getConnection()  {
        if (victors.size() == 0){
            JdbcPool.loadConfiguration();
        }
        if (victors.size() > 0){
            //取出一個 Connection,並給final?
            final Connection connection = victors.remove(0);
            //關鍵的動態代理技術,實現修改connection的close方法
            return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    if(!method.getName().equals("close")){
                        return method.invoke(connection, args);
                    }else{
                        //如果調用的是Connection對象的close方法,就把conn還給數據庫連接池
                        victors.addElement(connection);
                        System.out.println(connection + "被還給Connections數據庫連接池了!!");
                        System.out.println("Connections數據庫連接池大小爲" + victors.size());
                        return null;
                    }
                }
            });
        }else {
            System.out.println("日誌--鏈接超時!");
            return  null;
        }
    }
    public static void release(Connection connection, Statement statement,ResultSet resultSet){
        //先開後關
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }




//===========================實現的方法========================


                               @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

3.配置文件

配置文件:jdbcPoolConf.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bmft_blog?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
user=root
password=123456
jdbcPoolInitSize=10

4.效果

Run:(每個人數據庫不一樣,測試類請自己書寫一個,這裏測試類就不展示了)
在這裏插入圖片描述

三、常用的開源數據庫連接池

(這裏列一個綱領,具體的搜索我的博客)

1,DBCP

併發量低下,性能不要適用於小型系統,Tomcat內置

2.C3P0

單線程,性能差,適用於小型系統

3.Druid(阿里巴巴)

最好用的數據庫連接池,高性能,高併發,高拓展,分析監控設計,快速交互查詢,高可用(遇到一些情況,冗機還能運行)

四、如何使用Tomcat配置數據連接池

(這裏列一個綱領,具體的搜索我的博客)

五、JNDI技術簡介

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章