#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的批處理
addBatch()
executeBatch()
clearBatch()
##批處理實例 ###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(); } } }