数据库开发 - JDBC进阶

#JDBC进阶 ##业务场景(一) 在企业级业务场景中,我们会经常遇到我们编写的SQL语句,查询条件过弱,区分性不强,SQL所查询的内容过多。一方面,我们可以通过修改过滤条件来减少搜索内容,在一些特定的业务需求,缺需要这些内容。

过滤条件比较弱,一次可能不去较多记录!

输入图片说明

##业务场景(二) 数据统计需求,例如,在首页展示某些信息的排行榜。我们会扫描所有内容。

读取数据库表中所有的记录。

输入图片说明

##海量数据读取 读取千万条记录,(读取内容过多)会导致Java内存异常, 异常产生的原因,Java程序是运行在Java虚拟机JVM当中,JVM是有内存大小限制的。当我们把数据库当中的内容一次性读入到内存中,如果我们读取的数据一次性超过了内存大小的限制,将会得到内存溢出的异常。

输入图片说明

##游标 内存容量是有限的,我们每次只读取一部分数据进行处理,当处理完成后在读取下一部分的数据内容,这样我们就避免一次性载入太多的记录导致内存溢出。

游标是提供一种客户端读取部分服务器端结果集的机制。

我们把一个批次读取出来的记录称为Fetch Size 输入图片说明

##使用游标 两个关键步骤 ###在DB_URL中增加支持游标的参数 MySQL中,我们在DB_URL之后设置userCursorFetch=true开启游标功能。告诉JDBC开启游标
输入图片说明

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

转载于:https://my.oschina.net/hava/blog/749786

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值