數據庫開發 - JDBC進階

#JDBC進階 ##業務場景(一) 在企業級業務場景中,咱們會常常遇到咱們編寫的SQL語句,查詢條件過弱,區分性不強,SQL所查詢的內容過多。一方面,咱們能夠經過修改過濾條件來減小搜索內容,在一些特定的業務需求,缺須要這些內容。java

過濾條件比較弱,一次可能不去較多記錄!mysql

輸入圖片說明

##業務場景(二) 數據統計需求,例如,在首頁展現某些信息的排行榜。咱們會掃描全部內容。程序員

讀取數據庫表中全部的記錄。sql

輸入圖片說明

##海量數據讀取 讀取千萬條記錄,(讀取內容過多)會致使Java內存異常, 異常產生的緣由,Java程序是運行在Java虛擬機JVM當中,JVM是有內存大小限制的。當咱們把數據庫當中的內容一次性讀入到內存中,若是咱們讀取的數據一次性超過了內存大小的限制,將會獲得內存溢出的異常。數據庫

輸入圖片說明

##遊標 內存容量是有限的,咱們每次只讀取一部分數據進行處理,當處理完成後在讀取下一部分的數據內容,這樣咱們就避免一次性載入太多的記錄致使內存溢出。服務器

遊標是提供一種客戶端讀取部分服務器端結果集的機制。函數

咱們把一個批次讀取出來的記錄稱爲Fetch Size 輸入圖片說明post

##使用遊標 兩個關鍵步驟 ###在DB_URL中增長支持遊標的參數 MySQL中,咱們在DB_URL以後設置userCursorFetch=true開啓遊標功能。告訴JDBC開啓遊標
輸入圖片說明fetch

##PreparedStatement接口 PreparedStatement接口,繼承於Statement接口。能夠直接使用PreparedStatement接口替換Statement接口。PreparedStatement接口相比Statement接口,要求程序員在生成Statement的時候生成參數格式化的SQL語句。也就是說where的過濾條件都是經過的形式來表示的。後續,經過PreparedStatement的setString或者setInt等方法設置值。而後進行執行。編碼

輸入圖片說明

PreparedStatement接口,有setFetchSize函數,能夠設置客戶端每次取回的數量。

##遊標實例

String DB_URL_fetch = DB_URL + "?userCursorFetch=true";
            System.out.println("[DB_URL_fetch]:" + DB_URL_fetch);
//            connection = DriverManager.getConnection(DB_URL,USER,PASSWORD);
            connection = DriverManager.getConnection(DB_URL_fetch,USER,PASSWORD);

打印輸出

[DB_URL_fetch]:jdbc:mysql://192.168.1.200/test?userCursorFetch=true

###修改運行SQL部分

//            statement = connection.createStatement();
            preparedStatement = connection.prepareStatement("SELECT userName FROM user");
            preparedStatement.setFetchSize(1);
            resultSet = preparedStatement.executeQuery("SELECT userName FROM user");

#業務場景(三) 讀取數據庫當中,某字段可能會出現大字段內容,好比說文章、博客。在數據庫當中某一列,保存了很是大的字段。存儲文章、博客內容。有的系統會在數據庫當中存儲圖片。儘管咱們不推薦在數據庫中存儲圖片資源,等大對象。

輸入圖片說明

##大對象讀取 某行的某列信息內容,太過巨大,讀取有可能形成內存溢出問題。

輸入圖片說明 #流方式 咱們經過一種叫流的方式,解決列內容過多的問題。將大字段的內容,以二進制流的方式,按照區間進行劃分,劃分多個區間,每次讀取一個區間,進行處理。當一個區間處理結束,在讀取下一個區間內容。

輸入圖片說明

##使用流方式 由原來resultSet對象的getString()等方式,使用getBinaryStream()的方式讀取列信息。以後操做inputStream對象,進行數據內容讀取。

輸入圖片說明

#業務場景(四) - 批處理 數據錄入的業務場景,咱們須要把大量輸入錄入到系統當中。

輸入圖片說明

若是咱們使用for循環的方式執行SQL,咱們會發現速度很是慢。主要咱們執行update操做時,都須要發送SQL+執行SQL。
輸入圖片說明

##批處理 更加高效的方式-批處理,一次發送多條SQL,插入多條數據內容。

輸入圖片說明 ##Statement的批處理

  • Statement
    preparedStatement繼承於Statement,因此一樣能使用如下方法。
    • addBatch()
      把SQL打包成執行單元,把SQL加入到Batch中
    • executeBatch()
      執行Batch中的多條SQL
    • clearBatch()
      當執行結束後,清空Batch,爲下次Batch作準備。

##批處理實例 ###for循環方式提交

for(String user : users) {
                String sql = "INSERT INTO user (userName) VALUE (" + user + ")";
                statement.executeUpdate(sql);

            }

###批處理方式提交

Iterator iterator = users.iterator();

            int batchsize = 10;
            for(int index=0;index < users.size();index += batchsize)
            {
                for(int jndex=0;jndex < batchsize;jndex++)
                {
                    if(iterator.hasNext())
                    {
                        String user = iterator.next().toString();
                        String sql = "INSERT INTO user (userName) VALUE (" + user + ")";
                        statement.addBatch(sql);
                    }
                }
                //execute batch
                statement.executeBatch();
                //clear for the next batch
                statement.clearBatch();
            }

###時間監控代碼與循環一千次的執行時間差

Long begin = System.currentTimeMillis();
            // Dosomething
            Long end = System.currentTimeMillis();
            System.out.println("[end - begin]:" + (end - begin));

執行後的時間差值

[end - begin]:5321
[end - begin]:3136

#業務場景(五) - 中文 若是碰到JDBC中的字符集和存儲當中的字符集不統一,會獲取亂碼。 ##字符集設置 ###數據庫字符編碼 MySQL容許用戶設置server級別的數據庫編碼,也能夠設置數據庫級的編碼,容許設置表級別的編碼

優先級 列 > 表 > 數據庫 > 服務

輸入圖片說明

##JDBC設置 知道如上編碼,咱們JDBC的編碼須要設置成數據庫內部編碼一致,則咱們就不會獲取亂碼結果。

在DB_URL後面添加編碼參數,網易建議添加UTF8做爲統一的編碼格式。

輸入圖片說明

#附錄 ##FetchSize & preparedStatement的HelloJDBC

package com.hava.jdbc;

import java.sql.*;

/**
 * Created by zhanpeng on 2016/9/21.
 */
public class HelloJDBC {

//    static final String JDBC_DRIVER = "org.postgresql.Driver";
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

//    static final String DB_URL = "jdbc:postgresql://192.168.1.200/test";
    static final String DB_URL = "jdbc:mysql://192.168.1.200/test";

//    static final String USER = "postgres";
    static final String USER = "root";

//    static final String PASSWORD = "";
    static final String PASSWORD = "dVHJtG0T:pf*";

    public static void helloworld() throws ClassNotFoundException {

        Connection connection = null;

        Statement statement = null;
        //Fetch Statement
        PreparedStatement preparedStatement = null;

        ResultSet resultSet = null;


        // 1. add Driver
        Class.forName(JDBC_DRIVER);

        // 2. create db connnection
        try {
            // add the fetch value for db_url
            String DB_URL_fetch = DB_URL + "?userCursorFetch=true";
            System.out.println("[DB_URL_fetch]:" + DB_URL_fetch);
//            connection = DriverManager.getConnection(DB_URL,USER,PASSWORD);
            connection = DriverManager.getConnection(DB_URL_fetch,USER,PASSWORD);
            System.out.println("getConnection");

            // 3.run SQL

//            statement = connection.createStatement();
            preparedStatement = connection.prepareStatement("SELECT userName FROM user");
            preparedStatement.setFetchSize(1);
//            resultSet = statement.executeQuery("SELECT \"userName\" FROM \"public\".\"user\"");
            resultSet = preparedStatement.executeQuery("SELECT userName FROM user");

            // 4.get userName
            while(resultSet.next())
            {
                Integer index = resultSet.getRow();
                String value = resultSet.getString("userName");
                System.out.println("resultSet [row]:" + index + " [value]:" + value);
            }
        } catch (SQLException e) {
            // Exception
            e.printStackTrace();
        } finally {
            try {

                // 5. close connection
                if(connection != null)
                    connection.close();
                if(statement != null)
                    statement.close();
                if(resultSet != null)
                    resultSet.close();

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

##批處理

public static void batch(Set<String> users) throws ClassNotFoundException {
        Connection connection = null;

        Statement statement = null;
        //Fetch Statement
//        PreparedStatement preparedStatement = null;

        ResultSet resultSet = null;


        // 1. add Driver
        Class.forName(JDBC_DRIVER);

        // 2. create db connnection
        try {
            // add the fetch value for db_url
//            String DB_URL_fetch = DB_URL + "?userCursorFetch=true";
//            System.out.println("[DB_URL_fetch]:" + DB_URL_fetch);
            connection = DriverManager.getConnection(DB_URL,USER,PASSWORD);
//            connection = DriverManager.getConnection(DB_URL_fetch,USER,PASSWORD);
            System.out.println("getConnection");

            // 3.run SQL

            statement = connection.createStatement();
//            preparedStatement = connection.prepareStatement("SELECT userName FROM user");
//            preparedStatement.setFetchSize(1);
//            resultSet = statement.executeQuery("SELECT \"userName\" FROM \"public\".\"user\"");
//            resultSet = preparedStatement.executeQuery("SELECT userName FROM user");
//
//            // 4.get userName
//            while(resultSet.next())
//            {
//                Integer index = resultSet.getRow();
//                String value = resultSet.getString("userName");
//                System.out.println("resultSet [row]:" + index + " [value]:" + value);
//            }

            Long begin = System.currentTimeMillis();


            for(String user : users) {
                String sql = "INSERT INTO user (userName) VALUE (" + user + ")";
                statement.executeUpdate(sql);

            }

            Long end = System.currentTimeMillis();
            System.out.println("[end - begin]:" + (end - begin));


            begin = System.currentTimeMillis();
            Iterator iterator = users.iterator();

            int batchsize = 10;
            for(int index=0;index < users.size();index += batchsize)
            {
                for(int jndex=0;jndex < batchsize;jndex++)
                {
                    if(iterator.hasNext())
                    {
                        String user = iterator.next().toString();
                        String sql = "INSERT INTO user (userName) VALUE (" + user + ")";
                        statement.addBatch(sql);
                    }
                }
                //execute batch
                statement.executeBatch();
                //clear for the next batch
                statement.clearBatch();
            }

            end = System.currentTimeMillis();
            System.out.println("[end - begin]:" + (end - begin));
//
        } catch (SQLException e) {
            // Exception
            e.printStackTrace();
        } finally {
            try {

                // 5. close connection
                if(connection != null)
                    connection.close();
                if(statement != null)
                    statement.close();
                if(resultSet != null)
                    resultSet.close();

            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
相關文章
相關標籤/搜索