1. 程式人生 > 其它 >javaweb-day06-jdbc連線池

javaweb-day06-jdbc連線池

技術標籤:mysql資料庫jdbc

JDBC連線池&JDBCTemplate

  • jdbc連線池
    • 程式和資料庫之間的連線是底層技術,每一次連線都比較耗時,而用完後又得關閉連線釋放資源,這樣反覆連線和釋放其實是很浪費時間的,因此引出一個連線池技術,來管理這些連線物件。連線物件被使用完後,會歸還給連線池,等待分配給下一次使用,而不是銷燬。
  • jdbcTemplate
    • jdbc操作中,很多的程式碼大量重複出現,其實我們寫熟練以後,發現只需要關注sql怎麼寫就可以,所以對重複出現的程式碼進行封裝來簡化jdbc的操作。

一.資料庫連線池

1. 概述

  • 打個比方,過獨木橋。

    沒有連線池時,一人一個獨木橋,過河就拆,所以每來一個人過河就要搭建一個新的獨木橋。

    有了連線池後,就相當於建了一座大橋,可以同時讓多個人通過,不需要一直建,一直拆。

  • 畫圖理解。

在這裡插入圖片描述

2. 程式碼實現介紹

  • java.sql.DataSuorce 介面,就是表示連線池

    • getConnection()方法 可以獲取連線物件
  • 資料來源介面的實現由連線池廠商實現

    • c3p0 古老的,常被hibernate框架使用
    • druid 阿里的產品,效率很高
  • 如果連線物件是由連線池得到的,那麼它的Connection.close方法將不再表示關閉連線,而是歸還連線物件到連線池。

3. c3p0連線池

3.1 基本使用

  • 導jar包 – 兩個連線池 一個數據庫驅動 共3個
  • 配置檔案簡介
<?xml version="1.0" encoding="utf-8" ?>
<c3p0-config> <!-- 使用預設的配置讀取連線池物件 --> <default-config> <!-- 連線引數 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db1</property> <property name="
user"
>
root</property> <property name="password">root</property> <!-- 連線池引數 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">10</property> <property name="checkoutTimeout">3000</property> </default-config> <named-config name="myc3p0"> <!-- 連線引數 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property> <property name="user">root</property> <property name="password">root</property> <!-- 連線池引數 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">20</property> <property name="checkoutTimeout">5000</property> </named-config> </c3p0-config>
  • 注意事項:

    1. c3p0-config.xml 檔名必須這麼命名
    2. c3p0-config.xml 檔案必須放在src目錄下,不能放在子目錄
  • 可能會出錯的地方

    • 配置檔案中書寫錯誤
      • 檔名或路徑錯誤
      • 資料庫連線四大引數書寫錯誤,或多加空格
    • 忘記匯入驅動jar包
    public static void main(String[] args) throws SQLException {
        //建立連線池資料來源物件
            ComboPooledDataSource ds = new ComboPooledDataSource();
        //獲得連線物件
            Connection con = ds.getConnection();
        //輸出連線物件的地址值表示連線正常
            System.out.println(con);
        }
    

3.2 熟悉配置檔案

  • 測試最大連線數

    //不給引數,預設使用default-config配置的資料來源
    ComboPooledDataSource ds = new ComboPooledDataSource();
    //迴圈建立11個連線物件
    for (int i=1;i<=11;i++){
            Connection con = ds.getConnection();
            System.out.println(i+":"+con);
             if(i==6){
                  con.close();//歸還第6個物件給連線池
              }
      }
    
  • 測試超時時間

  • 測試命名的資料來源

    ComboPooledDataSource ds = new ComboPooledDataSource("otherc3p0"); 
    

4. druid連線池

4.1 基本使用

  • 匯入jar包-- 1個

  • 定義配置檔案 druid.properties

  • 程式碼演示

    //1.匯入jar包,定義配置檔案
    //2.載入配置檔案
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); 		       pro.load(is);
    //3.獲取連線池物件
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    //4.獲取連線物件
    Connection con = ds.getConnection();
    System.out.println(con);
    

4.2 工具類

  • 程式碼演示

    public class JDBCUtil {
        //1.定義一個數據源成員屬性
        private static DataSource ds;
        //2.在靜態程式碼塊中載入配置檔案
        static {
            try {
                Properties pro = new Properties();
                InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
                pro.load(is);
            //3.建立連線池物件
                ds = DruidDataSourceFactory.createDataSource(pro);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //獲取連線物件的方法
        public static Connection getConnection() throws SQLException {
            return  ds.getConnection();
        }
        //獲取連線池物件的方法
        public static DataSource getDataSource(){
            return ds;
        }
        
    //釋放資源的方法
        public void close(Statement stmt, Connection con, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(con!=null){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

4.3 工具類測試

  • 程式碼演示–向account表中新增一條資料

    public static void main(String[] args) {
            Connection con=null;
            PreparedStatement pstmt=null;
            try {
                //1.獲取連線物件
                con = JDBCUtil.getConnection();
                //2.定義sql
                String sql="insert into account values (null,?,?)";
                //3.建立pstmt物件
                pstmt = con.prepareStatement(sql);
                //4.給?賦值
                pstmt.setString(1,"曹操");
                pstmt.setDouble(2,3000);
                //5.執行sql
                int count = pstmt.executeUpdate();
                System.out.println(count);
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                //6.釋放資源
                JDBCUtil.close(pstmt,con);
            }
        }
    

總結:

1.什麼是連線池

1.就是一個容器
2.容器中裝的是connection連線物件
3.這些連線物件建立後可以反覆被使用,並不會銷燬
4.它們是共享的

2.連線物件和連線池物件

connection 連線
DataSource 連線池 -- 資料來源

獲取;
DataSource ds=new DruidDataSource();
ds.getConnection();
-- 通過資料來源獲取資料,其實就是通過連線池獲取連線

3.常用的連線池

c3p0   hibernate 傳統的orm框架 
druid  國產的 阿里

4.連線池的好處

1.節約資源 提高效率

二.jdbcTemplate

1. 簡介

  • Spring框架對jdbc的簡單封裝,提供了一個JdbcTemplate物件
  • jdbcTemplate的若干方法
    • update 執行 dml增刪改
    • queryForMap() 查詢結果,將結果集封裝為map集合
    • queryForList() 查詢結果,將結果集封裝為list集合
    • queryForObject() 查詢結果集,將結果集封裝成某個資料型別
    • query() 查詢結果集,將結果集封裝為Javabean物件

2. 快速入門

  • 程式碼演示–修改曹操的金額為5000

    public static void main(String[] args) {
            //1.匯入jar包
            //2.建立jdbcTemplate物件
            JdbcTemplate template = new JdbcTemplate(JDBCUtil.getDataSource());
            //3.定義sql語句
            String sql="update account set balance=5000 where id=?";
            // 4.呼叫update方法,並給?賦值
            int count = template.update(sql, 3);
            System.out.println(count);
        }
    

3. jdbcTemplate綜合練習

  1. 修改id為1的資料
  2. 新增一條資料
  3. 刪除一條資料
  4. 查詢id為1的一條記錄,封裝成map
  5. 查詢id為1的一條記錄,封裝成Account
  6. 查詢所有記錄,封裝成list
  7. 查詢所有記錄,封裝成泛型為Account的List
  8. 查詢總記錄數
public class DruidDemo3 {

    private JdbcTemplate template= new JdbcTemplate(JDBCUtil.getDataSource());
    @Test//修改
    public void test1(){
        int count = template.update("update account set balance=? where id=?",888,1);
        System.out.println(count);
    }
    @Test//新增
    public void test2(){
        int count = template.update("insert account values (null,?,?)","哪吒",666);
        System.out.println(count);
    }
    @Test//刪除
    public void test3(){
        int count = template.update("delete from account where id=?",3);
        System.out.println(count);
    }
    @Test//查詢一條 封裝map
    public void test4(){
        Map<String, Object> map = template.queryForMap("select * from account where id=?", 1);
        System.out.println(map);
    }
    @Test//查詢一條 封裝javaBean
    public void test5(){
        Account account = template.queryForObject("select * from account where id=?", new BeanPropertyRowMapper<Account>(Account.class),2);
        System.out.println(account);
    }
    @Test//查詢所有,封裝成List中泛型為Map
    public void test6(){
        List<Map<String, Object>> list = template.queryForList("select * from account ");
        System.out.println(list);
    }
    @Test//查詢所有,封裝成List中泛型為JavaBean
    public void test7(){
        List<Account> list = template.query("select * from account ", new BeanPropertyRowMapper<Account>(Account.class));
        System.out.println(list);
    }
    @Test//查詢總記錄數
    public void test8(){
        Integer a = template.queryForObject("select count(*) from account ", Integer.class);
        System.out.println(a);
    }
}

補充

1.部門表和員工表的查詢並關聯封裝

 @Test//每一個員工和他對應得部門資訊
    public void test2(){
        List<Emp> emps = template.query("select * from emp ", new BeanPropertyRowMapper<Emp>(Emp.class));
        //關聯每個部門下 的多個員工資訊
        for (Emp emp : emps) {
            emp.setDept(template.queryForObject("select * from dept where id=?",new BeanPropertyRowMapper<Dept>(Dept.class),emp.getDept_id()));
        }
        //輸出
        System.out.println(emps);
    }

    @Test//查詢所有的部門下所有的員工
    public void test1(){
        List<Dept> depts = template.query("select * from dept ", new BeanPropertyRowMapper<Dept>(Dept.class));
        //關聯每個部門下 的多個員工資訊
        for (Dept dept : depts) {
            dept.setEmps(template.query("select * from emp where dept_id=?",new BeanPropertyRowMapper<Emp>(Emp.class),dept.getId()));
        }
        //輸出
        System.out.println(depts);
    }

2.三層架構

controller  控制層
service  業務層  --包含介面和實現類
dao   執行層   --包含介面和實現類

controller層 --呼叫--> service層 --呼叫--> dao層
注意:
	介面和實現類的正確命名

3.template結合BeanPropertyRowMapper封裝的模擬實現

@Test
    public void testQuery1(){
        List<Emp> emps = myQuery("SELECT * FROM EMP WHERE ID> ?", Emp.class, 3);
        System.out.println(emps);
    }

    // 結合反射和原始的jdbc模擬查詢和封裝的實現
    public <T> List<T> myQuery(String sql, Class<T> c,Object ...args){
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql:///db3","root","root");
            //3.獲取執行sql的物件
            PreparedStatement pstm = con.prepareStatement(sql);
            //4.給佔位符賦值
            for (int i = 0; i < args.length; i++) {
                pstm.setObject(i+1,args[i]);
            }
            //5.執行sql
            ResultSet rs = pstm.executeQuery();
            //6.處理結果集--拆開rs
            //元資料--可以獲取結果集中的列數,列名,列型別
            ResultSetMetaData md = rs.getMetaData();
            //獲取總列數
            int columnCount = md.getColumnCount();
            ArrayList<T> ts = new ArrayList<>();
            while (rs.next()){//外層迴圈遍歷每一行
                T t = c.newInstance();
                for (int i = 1; i <= columnCount; i++) {//外層迴圈遍歷每一行的每一個單元格
                    Object value = rs.getObject(i);
                    String columnName = md.getColumnName(i).toLowerCase();//獲取每一個列的列名--和T中的屬性名一致的
                    String columnName1 = md.getColumnLabel(i);//獲取每一個列的列名--和T中的屬性名一致的
                    String columnName2 = md.getColumnClassName(i);//獲取每一個列的列名--和T中的屬性名一致的
                    System.out.println(columnName+"--"+columnName1+"--"+columnName2);
                    Field f = c.getDeclaredField(columnName);
                    f.setAccessible(true);//開啟私有屬性的操作許可權
                    f.set(t,value);
                }
                ts.add(t);

            }
            return ts;

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