美文网首页
JDBC 进阶

JDBC 进阶

作者: 旦暮何枯 | 来源:发表于2019-03-25 15:14 被阅读0次

游标操作方式-分批查询

游标提供一种客户端读取部分服务器端结果集的机制。
当 sql 语句的匹配条件太弱时,sql 结果会返回大量的数据,就有可能导出出现内存溢出。所以就出现了将结果分批处理的方式;

流程:

1.在配置 JDBC URL 时,在最后加上参数: useCursorFetch=true 开启游标属性

static String DB_URL = "jdbc:mysql://localhost:3306/test?useCursorFetch=true"

2.创建 preparedSatement 对象,在使用 prepareStatement 方法创建对象时,预编译 sql 语句。

conn.prepareStatement(sql,游标类型,能否更新记录);
游标类型:
ResultSet.TYPE_FORWORD_ONLY:只进游标
ResultSet.TYPE_SCROLL_INSENSITIVE:可滚动。但是不受其他用户对数据库更改的影响。
ResultSet.TYPE_SCROLL_SENSITIVE:可滚动。当其他用户更改数据库时这个记录也会改变。
能否更新记录:
ResultSet.CONCUR_READ_ONLY,只读
ResultSet.CONCUR_UPDATABLE,可更新

3.使用 setFetchSize 方法,设置分批处理的结果数

4.通过 setString 方法传入条件参数,第一个参数表示 参数位置,第二个参数为条件值

preparedSatement 可以写动态参数化查询
preparedSatement 可以预编译 sql 语句
preparedSatement 可以防止SQL注入式攻击

代码实例:

import java.sql.*;

public class Main {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static String DB_URL = "jdbc:mysql://localhost:3306/test?useSSL=true";
    static final String USER = "root";
    static final String PASSWORD = "admin";

    public static void main(String[] args) throws ClassNotFoundException{
        Connection conn = null;
        Statement statement = null;
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
//      1. 装载数据库驱动程序;
        Class.forName(JDBC_DRIVER);
//      2. 通过JDBC建立数据库连接;
        try {
            //在 url 中 开启 游标属性
            DB_URL = DB_URL + "&useCursorFetch=true";
            conn = DriverManager.getConnection(DB_URL,USER,PASSWORD);
//      3.访问数据库,执行SQL语句;
//            statement = conn.createStatement();
//            rs = statement.executeQuery("select name from test.user ");
//          对 preparedStatement 的 sql 语句进行预编译, ? 表示参数
            preparedStatement = conn.prepareStatement("select  * from test.ipdata where id=? and startip = ?");
//            通过 preparedStatement 使用游标 进行分批查询语句
            preparedStatement.setFetchSize(1);
//            通过setInt 或者 setString 将,预编译的 sql 语句中的 条件参数传递进去
            preparedStatement.setInt(1,13);
            preparedStatement.setString(2,"16844800");
            rs = preparedStatement.executeQuery();
//      4.获得执行结果
            while(rs.next()) {
                System.out.println("Hello " + rs.getString("country"));
            }



        } catch (SQLException e) {
//            异常处理
            e.printStackTrace();
        } finally {
            // 5. 断开数据库连接,清理环境
            try {
                if(conn != null) {
                    conn.close();
                }
                if(statement != null) {
                    statement.close();
                }
                if(rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                // pass
            }

        }
    }
}

大对象读取-流方式

当读取大对象时,有可能出现对象内容太大,内存放不下,从而出现的内存溢出问题。

主要涉及方法 ResultSet.getBinaryStream() 方法。

流程

  1. 通过对 ResultSet 对象使用 getBinaryStream() 获取流对象。
  2. 每次读取流对象中的一行内容输出到外部文件中
  3. 重复2 步骤,直至读取完流对象内容。
public static void main(String[] args) throws ClassNotFoundException {
    Connection conn = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;

    Class.forName(JDBC_DRIVER);
    try {
        conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
//            创建 preparedStatement 对象
        preparedStatement = conn.prepareStatement("select * from blog where id = ?");
        preparedStatement.setInt(1, 1);
//            执行 sql
        resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
//                获取对象流
            InputStream in = resultSet.getBinaryStream("context");
//                将对象流写入文件
            File f = new File(FILE_URL);
            OutputStream out = new FileOutputStream(f);
            int temp = 0;
                while ((temp = in.read()) != -1) {//边读边写
                    out.write(temp);
                }
                in.close();
                out.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
                if (preparedStatement != null)
                    preparedStatement.close();
                if (resultSet != null)
                    resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    }
}

一条语句多条执行- sql 的批处理

流程:

  1. statement 对象使用 addBatch() 方法添加 sql 语句
  2. statement 对象使用 executeBatch() 方法执行所有添加的 sql 语句
  3. statement 对象使用 clearBatch() 方法清空已执行的 sql 语句
public class HelloBatch {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static String DB_URL = "jdbc:mysql://localhost:3306/test?useSSL=true";
    static final String USER = "root";
    static final String PASSWORD = "admin";

    static void insertUsers(Set<String> users) throws ClassNotFoundException{
        Connection conn = null;
        Statement statement = null;
        ResultSet rs = null;
//      1. 装载数据库驱动程序;
        Class.forName(JDBC_DRIVER);
//      2. 通过JDBC建立数据库连接;
        try {
            conn = DriverManager.getConnection(DB_URL,USER,PASSWORD);
//      3.访问数据库,执行SQL语句;
            statement = conn.createStatement();
//            添加 sql 语句到 Batch
            for (String user : users) {
                statement.addBatch("insert into user(name) values ('" + user + "')");
                System.out.println("insert into user(name) values (" + user + ")");
            }
//            批执行 sql 语句
            statement.executeBatch();
//            清空已执行语句
            statement.clearBatch();
        } catch (SQLException e) {
//            异常处理
            e.printStackTrace();
        } finally {
            // 5. 断开数据库连接,清理环境
            try {
                if(conn != null) {
                    conn.close();
                }
                if(statement != null) {
                    statement.close();
                }
                if(rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                // pass
            }

        }
    }

    public static void main(String[] args) throws ClassNotFoundException {
        Set<String> users = new HashSet<>();
        users.add("GuoYi");
        users.add("GuoEi");
        users.add("GuoSi");

        insertUsers(users);
    }

}

jdbc 设置字符集

在 JDBC URL 中添加参数 characterEncoding=utf8

数据库设置字符集

查看数据库各级字符集.png
『项目地址』:https://github.com/wengfe/JAVA/tree/master/HelloJDBC/src

相关文章

  • JDBC编程目录

    JDBC编程目录 SQL基础JDBC基础JDBC进阶

  • JDBC进阶

    我们使用JDBC操作数据库时,经常遇到性能问题,请你说明一下如何提升读取数据的性能,以及更新数据的性能? 考察点:...

  • JDBC 进阶

    游标操作方式-分批查询 游标提供一种客户端读取部分服务器端结果集的机制。当 sql 语句的匹配条件太弱时,sql ...

  • JDBC进阶

    数据库连接池 池化思想优点:1.减少创建和销毁的资源开销,提高效率2.控制服务器的内存开销,使程序更加稳定 数据库...

  • JDBC进阶学习笔记

    JDBC进阶 JDBC连接池 1. 常见的JDBC连接池 c3p0 开源连接池 druid 阿里的开源数据库连接池...

  • 深入理解MySQL---数据库知识最全整理,这些你都知道了吗?

    对于后端开发人员来说,经常会和数据打交道,今天总结下数据库相关的知识。包括MySQL,JDBC基础,JDBC进阶,...

  • JDBC 进阶——元数据

    本文包括:1、元数据- DatabaseMetaData2、元数据- ParameterMetaData3、元数据...

  • JDBC进阶-数据库连接池技术以及jdbcTemplate

    概述:上篇文章讲解了一下JDBC的一些基础知识,接下来我们来学习下JDBC进阶知识-数据库连接池以及JbdcTem...

  • java进阶学习整理JDBC

    1.认识JDBC JDBC(Java Data Base Connectivity,java数据库连接)是一种用于...

  • JDBC 进阶——连接池

    本文包括传统JDBC的缺点连接池原理自定义连接池开源数据库连接池DBCP连接池C3P0连接池Tomcat内置连接池...

网友评论

      本文标题:JDBC 进阶

      本文链接:https://www.haomeiwen.com/subject/ljtbvqtx.html