1. 程式人生 > 其它 >JDBC複習-資料庫連線池

JDBC複習-資料庫連線池

技術標籤:JDBC學習

此部落格僅為本人學習JDBC時所做記錄。

10-資料庫連線池

10.1 傳統連線的問題

這種模式開發,存在的問題:

  • 普通的JDBC資料庫連線使用 DriverManager 來獲取,每次向資料庫建立連線的時候都要將 Connection 載入到記憶體中,再驗證使用者名稱和密碼(得花費0.05s~1s的時間)。需要資料庫連線的時候,就向資料庫要求一個,執行完成後再斷開連線。這樣的方式將會消耗大量的資源和時間。**資料庫的連線資源並沒有得到很好的重複利用。**若同時有幾百人甚至幾千人線上,頻繁的進行資料庫連線操作將佔用很多的系統資源,嚴重的甚至會造成伺服器的崩潰。
  • **對於每一次資料庫連線,使用完後都得斷開。**否則,如果程式出現異常而未能關閉,將會導致資料庫系統中的記憶體洩漏,最終將導致重啟資料庫。(回憶:何為Java的記憶體洩漏?)
  • 這種開發不能控制被建立的連線物件數,系統資源會被毫無顧及的分配出去,如連線過多,也可能導致記憶體洩漏,伺服器崩潰。

10.2 如何解決傳統開發中的資料庫連線問題

使用資料庫連線池。

10.3 使用資料庫連線池的好處

1. 資源重用

由於資料庫連線得以重用,避免了頻繁建立,釋放連線引起的大量效能開銷。在減少系統消耗的基礎上,另一方面也增加了系統執行環境的平穩性。

2. 更快的系統反應速度

資料庫連線池在初始化過程中,往往已經建立了若干資料庫連線置於連線池中備用。此時連線的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連線,避免了資料庫連線初始化和釋放過程的時間開銷,從而減少了系統的響應時間

3. 新的資源分配手段

對於多應用共享同一資料庫的系統而言,可在應用層通過資料庫連線池的配置,實現某一應用最大可用資料庫連線數的限制,避免某一應用獨佔所有的資料庫資源

4. 統一的連線管理,避免資料庫連線洩漏

在較為完善的資料庫連線池實現中,可根據預先的佔用超時設定,強制回收被佔用連線,從而避免了常規資料庫連線操作中可能出現的資源洩露

簡單總結:

  1. 提高程式的響應速度(減少建立連線相應的時間)
  2. 降低資源的消耗(可以重複使用)
  3. 便於連線的管理

10.4 實現的方式

  1. DBCP 是Apache提供的資料庫連線池。tomcat 伺服器自帶dbcp資料庫連線池。速度相對c3p0較快,但因自身存在BUG,Hibernate3已不再提供支援。
  2. C3P0 是一個開源組織提供的一個數據庫連線池,**速度相對較慢,穩定性還可以。**hibernate官方推薦使用
  3. Proxool 是sourceforge下的一個開源專案資料庫連線池,有監控連線池狀態的功能,穩定性較c3p0差一點
  4. BoneCP 是一個開源組織提供的資料庫連線池,速度快
  5. Druid 是阿里提供的資料庫連線池,據說是集DBCP 、C3P0 、Proxool 優點於一身的資料庫連線池,但是速度不確定是否有BoneCP快

10.5 C3P0

  1. 匯入jar包

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-XyCCZTi3-1608480337352)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181229297.png)]

  2. 測試連線的程式碼

    /**
     * 使用C3P0的資料庫連線池技術
     */
    //連線池只需要提供一個
    private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
    public static Connection getConnection1() throws SQLException {
        Connection conn = cpds.getConnection();
        return conn;
    }
    
  3. 配置檔案

    <?xml version="1.0" encoding="UTF-8"?>
    
        <c3p0-config>
            <named-config name="helloc3p0">
                <!--提供獲取連線的4個基本資訊-->
                <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
                <property name="jdbcUrl">jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>
                <property name="user">root</property>
                <property name="password">*****</property>
    
                <!--提供資料庫連線池管理的4個基本資訊-->
    
                <!-- 當資料庫連線池中的連線數不夠時,c3p0一次性向資料庫伺服器申請的連線數 -->
                <property name="acquireIncrement">5</property>
                <!-- c3p0資料庫連線池中初始化時的連線數 -->
                <property name="initialPoolSize">10</property>
                <!-- c3p0資料庫連線池中維護的最少的連線數 -->
                <property name="minPoolSize">10</property>
                <!-- c3p0資料庫連線池中維護的最多的連線數 -->
                <property name="maxPoolSize">100</property>
                <!-- c3p0資料庫連線池中維護的最多的statement的個數 -->
                <property name="maxStatements">50</property>
                <!-- 每個連線中可以最多使用的Statement的個數 -->
                <property name="maxStatementsPerConnection">2</property>
    
            </named-config>
        </c3p0-config>
    

10.6 DBCP

  1. 匯入jar包

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-9MgpDrRW-1608480337353)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181648502.png)]

  2. 測試連線的程式碼

     /**
         * 使用DBCP資料庫連線池技術獲取資料庫連線
         * @return
         * @throws Exception
         */
        //建立一個DBCP資料庫連線池
        private static DataSource source;
        static {
            try {
                Properties pros = new Properties();
    //        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
                FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));
                pros.load(is);
                //建立DBCP資料庫連線池
                source = BasicDataSourceFactory.createDataSource(pros);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    public static Connection getConnection2() throws Exception {
    
            Connection conn = source.getConnection();
            System.out.println(conn);
            return conn;
        }
    
  3. 配置檔案

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username=root
    password=****
    initialSize=10
    

10.7 Druid(最常用)

  1. 匯入jar包

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-T24M41Wq-1608480337353)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181945760.png)]

  2. 測試連線的程式碼

    /**
         * 使用Druid資料庫連線池技術
         */
    
        private  static DataSource source1;
        static {
            Properties pros = new Properties();
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
            try {
                pros.load(is);
                //獲取Druid資料庫連線池
                source1 = DruidDataSourceFactory.createDataSource(pros);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection3() throws Exception {
            Connection conn = source1.getConnection();
            return conn;
        }
    
  3. 配置檔案

    #等號最好不要有空格,否則會產生歧義,比如說密碼是否包括空格呢?
    url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username=root
    password=****
    driverClassName=com.mysql.cj.jdbc.Driver
    
    initialSize=10
    maxActive=10
    

11-DBUtils提供的jar包實現CRUD操作

11.1 匯入jar包

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-RQEDJ5Cc-1608480337354)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220182122531.png)]

11.2 使用現有的jar中的QueryRunner測試增、刪、改的操作
//測試插入
    @Test
    public  void testInsert() {

        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "insert into customers(name,email,birth) values(?,?,?)";
            int insertCount = runner.update(conn, sql, "蔡徐坤", "[email protected]", "1999-09-09");
            System.out.println("添加了"+insertCount+"條記錄");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }
11.3 使用現有的jar中的QueryRunner測試查詢的操作
//測試查詢

    /**
     * BeanHandler:是ResultSetHandler介面的實現類,用於封裝表中的一條記錄
     * @throws Exception
     */
    @Test
    public  void testQuery1() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
            Customer customer = runner.query(conn, sql, handler, 25);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * BeanListHandler:是ResultSetHandler介面的實現類,用於封裝表中的多條記錄構成的集合
     * @throws Exception
     */
    @Test
    public  void testQuery2() throws Exception {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id < ? ";
            BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
            List<Customer> customerList = runner.query(conn, sql, handler, 25);
            customerList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * MapHandler:是ResultSetHandler介面的實現類,對應表中的一條記錄,將欄位及相應欄位的值作為map中的鍵和值
     * @throws Exception
     */
    @Test
    public  void testQuery3() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            MapHandler handler = new MapHandler();
            Map<String,Object> map = runner.query(conn, sql, handler, 25);
            System.out.println(map);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * MapListHandler:是ResultSetHandler介面的實現類,對應表中的多條記錄,將欄位及相應欄位的值作為map中的鍵和值,將這些map新增到List中
     */
    @Test
    public  void testQuery4() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            MapListHandler handler = new MapListHandler();
            List<Map<String, Object>> mapList = runner.query(conn, sql, handler, 25);
            mapList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * ScalarHandler:是ResultSetHandler介面的實現類,用於查詢特殊值
     */
    @Test
    public  void testQuery5() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select count(*) from customers";
            ScalarHandler handler = new ScalarHandler();
            Long count = (Long) runner.query(conn, sql, handler);
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    @Test
    public  void testQuery6() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select max(birth) from customers";
            ScalarHandler handler = new ScalarHandler();
            Date max = (Date) runner.query(conn, sql, handler);
            System.out.println(max);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * 自定義ResultSetHandler實現類
     */
    @Test
    public  void testQuery7() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ?";
            ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>() {
                @Override
                public Customer handle(ResultSet resultSet) throws SQLException {
                    if(resultSet.next()){
                        int id = resultSet.getInt(1);
                        String name = resultSet.getString(2);
                        String email = resultSet.getString(3);
                        Date birth = resultSet.getDate(4);
                        Customer customer = new Customer(id,name,email,birth);
                        return customer;
                    }
                    return null;
                }
            };
            Customer customer = runner.query(conn, sql, handler, 12);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }
11.4 使用dbutils.jar包中的dbutils工具類實現連線等資源的關閉
 public static void closeResource1(Connection conn, Statement ps, ResultSet rs){
//        try {
//            DbUtils.close(conn);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            DbUtils.close(ps);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            DbUtils.close(rs);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
        DbUtils.closeQuietly(conn,ps,rs);
    }

完結撒花❀❀❀❀❀❀❀❀