成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JDBC【數(shù)據(jù)庫連接池、DbUtils框架、分頁】

dinfer / 1190人閱讀

摘要:數(shù)據(jù)庫連接池什么是數(shù)據(jù)庫連接池簡單來說數(shù)據(jù)庫連接池就是提供連接的。。。

1.數(shù)據(jù)庫連接池 什么是數(shù)據(jù)庫連接池

簡單來說:數(shù)據(jù)庫連接池就是提供連接的。。。

為什么我們要使用數(shù)據(jù)庫連接池

數(shù)據(jù)庫的連接的建立和關(guān)閉是非常消耗資源的

頻繁地打開、關(guān)閉連接造成系統(tǒng)性能低下

編寫連接池

編寫連接池需實(shí)現(xiàn)java.sql.DataSource接口

創(chuàng)建批量的Connection用LinkedList保存【既然是個池,當(dāng)然用集合保存、、LinkedList底層是鏈表,對增刪性能較好】

實(shí)現(xiàn)getConnetion(),讓getConnection()每次調(diào)用,都是在LinkedList中取一個Connection返回給用戶

調(diào)用Connection.close()方法,Connction返回給LinkedList



    private static LinkedList list = new LinkedList<>();
    
    //獲取連接只需要一次就夠了,所以用static代碼塊
    static {
        //讀取文件配置
        InputStream inputStream = Demo1.class.getClassLoader().getResourceAsStream("db.properties");

        Properties properties = new Properties();
        try {
            properties.load(inputStream);
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String driver = properties.getProperty("driver");
            String password = properties.getProperty("password");

            //加載驅(qū)動
            Class.forName(driver);

            //獲取多個連接,保存在LinkedList集合中
            for (int i = 0; i < 10; i++) {
                Connection connection = DriverManager.getConnection(url, username, password);
                list.add(connection);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    //重寫Connection方法,用戶獲取連接應(yīng)該從LinkedList中給他
    @Override
    public Connection getConnection() throws SQLException {
        System.out.println(list.size());
        System.out.println(list);

       //先判斷LinkedList是否存在連接
       return list.size() > 0 ? list.removeFirst() : null; 
    }


我們已經(jīng)完成前三步了,現(xiàn)在問題來了。我們調(diào)用Conncetion.close()方法,是把數(shù)據(jù)庫的物理連接關(guān)掉,而不是返回給LinkedList的

解決思路:

寫一個Connection子類,覆蓋close()方法

寫一個Connection包裝類,增強(qiáng)close()方法

用動態(tài)代理,返回一個代理對象出去,攔截close()方法的調(diào)用,對close()增強(qiáng)

分析第一個思路:

Connection是通過數(shù)據(jù)庫驅(qū)動加載的,保存了數(shù)據(jù)的信息。寫一個子類Connection,new出對象,子類的Connction無法直接繼承父類的數(shù)據(jù)信息,也就是說子類的Connection是無法連接數(shù)據(jù)庫的,更別談覆蓋close()方法了。

分析第二個思路:

寫一個Connection包裝類。

寫一個類,實(shí)現(xiàn)與被增強(qiáng)對象的相同接口【Connection接口】

定義一個變量,指向被增強(qiáng)的對象

定義構(gòu)造方法,接收被增強(qiáng)對象

覆蓋想增強(qiáng)的方法

對于不想增強(qiáng)的方法,直接調(diào)用被增強(qiáng)對象的方法

這個思路本身是沒什么毛病的,就是實(shí)現(xiàn)接口時,方法太多了!,所以我們也不使用此方法

分析第三個思路代碼實(shí)現(xiàn):

    @Override
    public Connection getConnection() throws SQLException {

        if (list.size() > 0) {
            final Connection connection = list.removeFirst();

            //看看池的大小
            System.out.println(list.size());

            //返回一個動態(tài)代理對象
            return (Connection) Proxy.newProxyInstance(Demo1.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                    //如果不是調(diào)用close方法,就按照正常的來調(diào)用
                    if (!method.getName().equals("close")) {
                        return method.invoke(connection, args);
                    } else {

                        //進(jìn)到這里來,說明調(diào)用的是close方法
                        list.add(connection);

                        //再看看池的大小
                        System.out.println(list.size());

                    }
                    return null;
                }

            });
        }
        return null;
    }

我們上面已經(jīng)能夠簡單編寫一個線程池了。下面我們來使用一下開源數(shù)據(jù)庫連接池

DBCP

使用DBCP數(shù)據(jù)源的步驟:

導(dǎo)入兩個jar包【Commons-dbcp.jar和Commons-pool.jar】

讀取配置文件

獲取BasicDataSourceFactory對象

創(chuàng)建DataSource對象

    private static DataSource dataSource = null;

    static {
        try {
            //讀取配置文件
            InputStream inputStream = Demo3.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            //獲取工廠對象
            BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory();
            dataSource = basicDataSourceFactory.createDataSource(properties);

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

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();

    }

    //這里釋放資源不是把數(shù)據(jù)庫的物理連接釋放了,是把連接歸還給連接池【連接池的Connection內(nèi)部自己做好了】
    public static void release(Connection conn, Statement st, ResultSet rs) {

        if (rs != null) {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (st != null) {
            try {
                st.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

C3P0

C3P0數(shù)據(jù)源的性能更勝一籌,并且它可以使用XML配置文件配置信息!

步驟:

導(dǎo)入開發(fā)包【c3p0-0.9.2-pre1.jar】和【mchange-commons-0.2.jar】

導(dǎo)入XML配置文件【可以在程序中自己一個一個配,C3P0的doc中的Configuration有XML文件的事例】

new出ComboPooledDataSource對象

    private static ComboPooledDataSource comboPooledDataSource = null;

    static {
        //如果我什么都不指定,就是使用XML默認(rèn)的配置,這里我指定的是oracle的
        comboPooledDataSource = new ComboPooledDataSource("oracle");
    }

    public static Connection getConnection() throws SQLException {
        return comboPooledDataSource.getConnection();
    }
Tomcat數(shù)據(jù)源

Tomcat服務(wù)器也給我們提供了連接池,內(nèi)部其實(shí)就是DBCP

步驟:

在META-INF目錄下配置context.xml文件【文件內(nèi)容可以在tomcat默認(rèn)頁面的 JNDI Resources下Configure Tomcat"s Resource Factory找到】

導(dǎo)入Mysql或oracle開發(fā)包到tomcat的lib目錄下

初始化JNDI->獲取JNDI容器->檢索以XXX為名字在JNDI容器存放的連接池

context.xml文件的配置:



  

        try {

            //初始化JNDI容器
            Context initCtx = new InitialContext();

            //獲取到JNDI容器
            Context envCtx = (Context) initCtx.lookup("java:comp/env");

            //掃描以jdbc/EmployeeDB名字綁定在JNDI容器下的連接池
            DataSource ds = (DataSource)
                    envCtx.lookup("jdbc/EmployeeDB");

            Connection conn = ds.getConnection();
            System.out.println(conn);

        } 

使用dbutils框架

dbutils它是對JDBC的簡單封裝,極大簡化jdbc編碼的工作量

DbUtils類

提供了關(guān)閉連接,裝載JDBC驅(qū)動,回滾提交事務(wù)等方法的工具類【比較少使用,因?yàn)槲覀儗W(xué)了連接池,就應(yīng)該使用連接池連接數(shù)據(jù)庫】

QueryRunner類

該類簡化了SQL查詢,配合ResultSetHandler使用,可以完成大部分的數(shù)據(jù)庫操作,重載了許多的查詢,更新,批處理方法。大大減少了代碼量

ResultSetHandler接口

該接口規(guī)范了對ResultSet的操作,要對結(jié)果集進(jìn)行什么操作,傳入ResultSetHandler接口的實(shí)現(xiàn)類即可。

ArrayHandler:把結(jié)果集中的第一行數(shù)據(jù)轉(zhuǎn)成對象數(shù)組。

ArrayListHandler:把結(jié)果集中的每一行數(shù)據(jù)都轉(zhuǎn)成一個數(shù)組,再存放到List中。

BeanHandler:將結(jié)果集中的第一行數(shù)據(jù)封裝到一個對應(yīng)的JavaBean實(shí)例中。

BeanListHandler:將結(jié)果集中的每一行數(shù)據(jù)都封裝到一個對應(yīng)的JavaBean實(shí)例中,存放到List里。

ColumnListHandler:將結(jié)果集中某一列的數(shù)據(jù)存放到List中。

KeyedHandler(name):將結(jié)果集中的每一行數(shù)據(jù)都封裝到一個Map里,再把這些map再存到一個map里,其key為指定的key。

MapHandler:將結(jié)果集中的第一行數(shù)據(jù)封裝到一個Map里,key是列名,value就是對應(yīng)的值。

MapListHandler:將結(jié)果集中的每一行數(shù)據(jù)都封裝到一個Map里,然后再存放到List

ScalarHandler 將ResultSet的一個列到一個對象中。

使用DbUtils框架對數(shù)據(jù)庫的CRUD


/*
* 使用DbUtils框架對數(shù)據(jù)庫的CRUD
* 批處理
*
* */
public class Test {

    @org.junit.Test
    public void add() throws SQLException {

        //創(chuàng)建出QueryRunner對象
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "INSERT INTO student (id,name) VALUES(?,?)";

        //我們發(fā)現(xiàn)query()方法有的需要傳入Connection對象,有的不需要傳入
        //區(qū)別:你傳入Connection對象是需要你來銷毀該Connection,你不傳入,由程序幫你把Connection放回到連接池中
        queryRunner.update(sql, new Object[]{"100", "zhongfucheng"});

    }

    @org.junit.Test
    public void query()throws SQLException {

        //創(chuàng)建出QueryRunner對象
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "SELECT * FROM student";

        List list = (List) queryRunner.query(sql, new BeanListHandler(Student.class));
        System.out.println(list.size());

    }

    @org.junit.Test
    public void delete() throws SQLException {
        //創(chuàng)建出QueryRunner對象
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "DELETE FROM student WHERE id="100"";

        queryRunner.update(sql);
    }

    @org.junit.Test
    public void update() throws SQLException {
        //創(chuàng)建出QueryRunner對象
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "UPDATE student SET name=? WHERE id=?";

        queryRunner.update(sql, new Object[]{"zhongfuchengaaa", 1});
    }

    @org.junit.Test
    public void batch() throws SQLException {
        //創(chuàng)建出QueryRunner對象
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "INSERT INTO student (name,id) VALUES(?,?)";

        Object[][] objects = new Object[10][];
        for (int i = 0; i < 10; i++) {
            objects[i] = new Object[]{"aaa", i + 300};
        }
        queryRunner.batch(sql, objects);
    }

}

分頁

分頁技術(shù)是非常常見的,在搜索引擎下搜索頁面,不可能把全部數(shù)據(jù)都顯示在一個頁面里邊。所以我們用到了分頁技術(shù)。

Oracle實(shí)現(xiàn)分頁
    /*
      Oracle分頁語法:
        @lineSize---每頁顯示數(shù)據(jù)行數(shù)
        @currentPage----當(dāng)前所在頁
    
    */
    SELECT *FROM (
        SELECT 列名,列名,ROWNUM rn
        FROM 表名
        WHERE ROWNUM<=(currentPage*lineSize)) temp
    
    WHERE temp.rn>(currentPage-1)*lineSize;

Oracle分頁原理簡單解釋

    /*
      Oracle分頁:
        Oracle的分頁依賴于ROWNUM這個偽列,ROWNUM主要作用就是產(chǎn)生行號。
    
      分頁原理:
        1:子查詢查出前n行數(shù)據(jù),ROWNUM產(chǎn)生前N行的行號
        2:使用子查詢產(chǎn)生ROWNUM的行號,通過外部的篩選出想要的數(shù)據(jù)
    
      例子:
        我現(xiàn)在規(guī)定每頁顯示5行數(shù)據(jù)【lineSize=5】,我要查詢第2頁的數(shù)據(jù)【currentPage=2】
        注:【對照著語法來看】
    
      實(shí)現(xiàn):
        1:子查詢查出前10條數(shù)據(jù)【ROWNUM<=10】
        2:外部篩選出后面5條數(shù)據(jù)【ROWNUM>5】
        3:這樣我們就取到了后面5條的數(shù)據(jù)
    */
Mysql實(shí)現(xiàn)分頁
    /*
      Mysql分頁語法:
      @start---偏移量,不設(shè)置就是從0開始【也就是(currentPage-1)*lineSize】
      @length---長度,取多少行數(shù)據(jù)
    
    */
    SELECT *
    FROM 表名
    LIMIT [START], length;
    
    /*
      例子:
        我現(xiàn)在規(guī)定每頁顯示5行數(shù)據(jù),我要查詢第2頁的數(shù)據(jù)
    
      分析:
        1:第2頁的數(shù)據(jù)其實(shí)就是從第6條數(shù)據(jù)開始,取5條
    
      實(shí)現(xiàn):
        1:start為5【偏移量從0開始】
        2:length為5

*/

總結(jié):

Mysql從(currentPage-1)*lineSize開始取數(shù)據(jù),取lineSize條數(shù)據(jù)

Oracle先獲取currentPagelineSize條數(shù)據(jù),從(currentPage-1)lineSize開始取數(shù)據(jù)

使用JDBC連接數(shù)據(jù)庫實(shí)現(xiàn)分頁

下面是常見的分頁圖片

配合圖片,看下我們的需求是什么:

算出有多少頁的數(shù)據(jù),顯示在頁面上

根據(jù)頁碼,從數(shù)據(jù)庫顯示相對應(yīng)的數(shù)據(jù)。

分析:

算出有多少頁數(shù)據(jù)這是非常簡單的【在數(shù)據(jù)庫中查詢有多少條記錄,你每頁顯示多少條記錄,就可以算出有多少頁數(shù)據(jù)了】

使用Mysql或Oracle的分頁語法即可

通過上面分析,我們會發(fā)現(xiàn)需要用到4個變量

currentPage--當(dāng)前頁【由用戶決定的】

totalRecord--總數(shù)據(jù)數(shù)【查詢表可知】

lineSize--每頁顯示數(shù)據(jù)的數(shù)量【由我們開發(fā)人員決定】

pageCount--頁數(shù)【totalRecord和lineSize決定】

        //每頁顯示3條數(shù)據(jù)
        int lineSize = 3;

        //總記錄數(shù)
        int totalRecord = getTotalRecord();

        //假設(shè)用戶指定的是第2頁
        int currentPage = 2;

        //一共有多少頁
        int pageCount = getPageCount(totalRecord, lineSize);

        //使用什么數(shù)據(jù)庫進(jìn)行分頁,記得要在JdbcUtils中改配置
        List list = getPageData2(currentPage, lineSize);
        for (Person person : list) {
            System.out.println(person);
        }

    }

    //使用JDBC連接Mysql數(shù)據(jù)庫實(shí)現(xiàn)分頁
    public static List getPageData(int currentPage, int lineSize) throws SQLException {

        //從哪個位置開始取數(shù)據(jù)
        int start = (currentPage - 1) * lineSize;

        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "SELECT name,address  FROM person LIMIT ?,?";

        List persons = (List) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{start, lineSize});
        return persons;

    }

    //使用JDBC連接Oracle數(shù)據(jù)庫實(shí)現(xiàn)分頁
    public static List getPageData2(int currentPage, int lineSize) throws SQLException {

        //從哪個位置開始取數(shù)據(jù)
        int start = (currentPage - 1) * lineSize;

        //讀取前N條數(shù)據(jù)
        int end = currentPage * lineSize;

        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "SELECT " +
                "  name, " +
                "  address " +
                "FROM ( " +
                "  SELECT " +
                "    name, " +
                "    address , " +
                "    ROWNUM rn " +
                "  FROM person " +
                "  WHERE ROWNUM <= ? " +
                ")temp WHERE temp.rn>?";

        List persons = (List) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{end, start});
        return persons;

    }

    public static int getPageCount(int totalRecord, int lineSize) {

        //簡單算法
        //return (totalRecord - 1) / lineSize + 1;

        //此算法比較好理解,把數(shù)據(jù)代代進(jìn)去就知道了。
        return totalRecord % lineSize == 0 ? (totalRecord / lineSize) : (totalRecord / lineSize) + 1;

    }


    public static int  getTotalRecord() throws SQLException {

        //使用DbUtils框架查詢數(shù)據(jù)庫表中有多少條數(shù)據(jù)
        QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
        String sql = "SELECT COUNT(*) FROM person";

        Object o = queryRunner.query(sql, new ScalarHandler());

        String ss = o.toString();
        int  s = Integer.parseInt(ss);
        return s;
    }

如果文章有錯的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章的同學(xué),可以關(guān)注微信公眾號:Java3y。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68503.html

相關(guān)文章

  • Java3y文章目錄導(dǎo)航

    摘要:前言由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時間才會更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號:Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡單 注解就這么簡單 Druid數(shù)據(jù)庫連接池...

    KevinYan 評論0 收藏0
  • Java編程基礎(chǔ)34——JDBC&DBUtil

    摘要:不用自己來創(chuàng)建,而是通過池來獲取對象使用完后,調(diào)用的方法也不會真的關(guān)閉,而是把歸還給池連接池技術(shù)可以完成對象的再次利用接口為數(shù)據(jù)庫連接池提供了公共的接口各個廠商需要讓自己的連接池實(shí)現(xiàn)這個接口。 1.DButils工具類的介紹個三個核心類 A: 概述 DBUtils是java編程中的數(shù)據(jù)庫操作實(shí)用工具,小巧簡單實(shí)用。 DBUtils封裝了對JDBC的操作,簡化了JDBC操作,可以少...

    svtter 評論0 收藏0
  • 1、DBUtils 2、連接

    摘要:不用自己來創(chuàng)建,而是通過池來獲取對象使用完后,調(diào)用的方法也不會真的關(guān)閉,而是把歸還給池連接池技術(shù)可以完成對象的再次利用接口為數(shù)據(jù)庫連接池提供了公共的接口各個廠商需要讓自己的連接池實(shí)現(xiàn)這個接口。 01DButils工具類的介紹個三個核心類 * A: DButils工具類的介紹個三個核心類 * a: 概述 * DBUtils是java編程中的數(shù)據(jù)庫操作實(shí)用工具,小巧...

    chuyao 評論0 收藏0
  • JavaWEB開發(fā)13——事務(wù)與連接

    摘要:一致性一個事務(wù)中,事務(wù)前后數(shù)據(jù)的完整性必須保持一致。持久性持久性是指一個事務(wù)一旦被提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,接下來即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響。 一、事務(wù)概述1.什么是事務(wù)一件事情有n個組成單元 要不這n個組成單元同時成功 要不n個單元就同時失敗就是將n個組成單元放到一個事務(wù)中2.mysql的事務(wù)默認(rèn)的事務(wù):一條sql語句就是一個事務(wù) 默認(rèn)就開啟事務(wù)并提交事...

    13651657101 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<