#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(); } } }