老师,关于批处理的疑问

老师,关于批处理的疑问

#  1、prepareStatement   也可以放在for循环外吧?我放在外面也可以执行呢?

    2、我把prepareStatement放在for循环内还是循环外,以及是否进行批处理,分开4种情况进行了测试,测试结果如下图,对结果有些疑问。
         (1)未进行批处理时,prepareStatement在循环外所花费的时间远小于在循环内所花费的时间,这节省的时间是否是因为prepareStatement在循环内时,需要创建10万个prepareStatement对象,而放在循环外时,则仅创建一个对象,所以节省了大量的创建对象花费的时间?
         (2)prepareStatement放在循环外时,进行批处理与未进行批处理所花费的时间比较接近,这个是为什么呢?循环内直接executeUpdate() 与 循环内添加addBatch()再循环外executeBatch(),这两种方式执行的具体原理是什么呢?
         (3) 为什么在进行批处理时,把preparestatement放在循环内比放在循环外花费的时间少呢?

       
         

http://img1.sycdn.imooc.com//climg/5fbe849609f9fa1406710169.jpg




package review;

import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;

public class insert {
    public static void tc1(){
        long startTime=new java.util.Date().getTime();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/jdbc?useSSl=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
            connection = DriverManager.getConnection(url, "root", "root");
            connection.setAutoCommit(false);
            String sql = "insert into goods(id,name,price,desp) values(?,?,?,?)";
            for(int i=10000;i<110000;i++) {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setInt(1,i);
                preparedStatement.setString(2,"员工"+i);
                preparedStatement.setFloat(3,i);
                preparedStatement.setString(4, "描述" + i);
                preparedStatement.executeUpdate();
            }
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if(connection!=null&!connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        long endTime=new java.util.Date().getTime();
        long time=endTime-startTime;
        System.out.println("未批处理,prepareStatement在循环内,花费时间:"+time);
    }

    public static void tc2(){
        long startTime=new java.util.Date().getTime();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/jdbc?useSSl=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
            connection = DriverManager.getConnection(url, "root", "root");
            connection.setAutoCommit(false);
            String sql = "insert into goods(id,name,price,desp) values(?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            for(int i=110000;i<210000;i++) {
                preparedStatement.setInt(1,i);
                preparedStatement.setString(2,"员工"+i);
                preparedStatement.setFloat(3,i);
                preparedStatement.setString(4, "描述" + i);
                preparedStatement.executeUpdate();
            }
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if(connection!=null&!connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        long endTime=new java.util.Date().getTime();
        long time=endTime-startTime;
        System.out.println("未批处理,prepareStatement在循环外,花费时间:"+time);
    }
    public static void tc3(){
        long startTime=new java.util.Date().getTime();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/jdbc?useSSl=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
            connection = DriverManager.getConnection(url, "root", "root");
            connection.setAutoCommit(false);
            String sql = "insert into goods(id,name,price,desp) values(?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            for(int i=210000;i<310000;i++) {
                preparedStatement.setInt(1,i);
                preparedStatement.setString(2,"员工"+i);
                preparedStatement.setFloat(3,i);
                preparedStatement.setString(4, "描述" + i);
                preparedStatement.addBatch();
            //    preparedStatement.executeUpdate();
            }
            preparedStatement.executeBatch();
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if(connection!=null&!connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        long endTime=new java.util.Date().getTime();
        long time=endTime-startTime;
        System.out.println("批处理,prepareStatement在循环外,花费时间:"+time);
    }
    public static void tc4(){
        long startTime=new java.util.Date().getTime();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/jdbc?useSSl=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
            connection = DriverManager.getConnection(url, "root", "root");
            connection.setAutoCommit(false);
            String sql = "insert into goods(id,name,price,desp) values(?,?,?,?)";
            for(int i=310000;i<410000;i++) {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setInt(1,i);
                preparedStatement.setString(2,"员工"+i);
                preparedStatement.setFloat(3,i);
                preparedStatement.setString(4, "描述" + i);
                preparedStatement.addBatch();
                //    preparedStatement.executeUpdate();
            }
            preparedStatement.executeBatch();
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if(connection!=null&!connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        long endTime=new java.util.Date().getTime();
        long time=endTime-startTime;
        System.out.println("批处理,prepareStatement在循环内,花费时间:"+time);
    }
    public static void main(String[] args) {
        tc1();
        tc2();
        tc3();
        tc4();
    }
}


正在回答

登陆购买课程后可参与讨论,去登陆

2回答

同学你好,如果将preparedStatement定义在循环内,实际添加的只有最后一条数据,并不是批量添加,如:

http://img1.sycdn.imooc.com//climg/600d58dd0966a47607800286.jpg

执行结果数量查询,tc3()方法的100000条数据,加上原有的4条数据,以及tc4()方法的最后一条数据,最后查询结果是100005条数据。

http://img1.sycdn.imooc.com//climg/600d594809ce600b04160284.jpg

这里的的消耗是指执行sql语句时,链接数据库和写入数据以及线程执行的消耗。

祝学习愉快~

  • 谁叫我这么坏 提问者 #1

    奥奥,谢谢老师,之前都没注意这个问题呢。。。。
    不过老师,为啥preparedStatement定义在循环外面就可以正常出结果,而定义在循环内就不可以了呢?

    2021-01-24 21:42:37
  • 同学你好,preparedStatement.addBatch();是将数据追加到preparedStatement中,如果在循环中定义preparedStatement,每次都是一个新的对象。所以执行sql时,就只有最后添加的数据。

    祝学习愉快~

    2021-01-25 10:13:17
好帮手慕小尤 2020-11-26 13:53:29

同学你好,1. 是的,prepareStatement可以在循环外。

2. 同学理解是正确的。

3. 执行时间并不是固定的,可能与电脑性能以及环境有所联系,所以会有一些差异。如下图所示:

http://img1.sycdn.imooc.com//climg/5fbf246309757cd004720098.jpg

4. 两种方式实现的原理:

    addBatch()把若干sql语句装载到一起,然后一次送到数据库执行,执行需要很短的时间,而pstmt.executeUpdate() 是一条一条发往数据库执行的 时间都消耗在数据库连接的传输上面。如:

    我这有一台超大功率的面粉加工机,前者相当于 把所有农户袋装的麦子收集起来用卡车一次送往加工厂 后者相当于农户排好队用同样的卡车一人一人的往加工厂送麦子 麦子加工5分钟完成,但是每个人到工厂就得3小时,我数据库执行效率再高也没用,时间都耗在传输的路上了!!

    这就出现了数据传输的性能瓶颈 addBatch就是为解决这样的问题而产生的!

5. 在批处理时,在循环外定义preparedstatement,消耗会比较大,导致时间长,而在循环内定义消耗少,所以时间会比较短。如:在循环外是一次性跑一万米,而循环内就是分开跑一万米(如:一次跑一百米,最后整合到一起所以消耗少)。

  • 提问者 谁叫我这么坏 #1

    老师,为啥在批处理时,在循环外定义preparedstatement,消耗会比较大,,而在循环内定义消耗少??这个消耗是指的什么啊?

    2021-01-24 18:08:21
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师