数据库开发 - 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();
            }
        }
    }
相关文章
相关标签/搜索