数据批量写入

数据批量写入

1.Statement 写入

@Test
public void testInsert2() {

    Connection conn = null;
    PreparedStatement ps = null;
    try {
        // 关闭自动提交
        conn.setAutoCommit(false);

        long start = System.currentTimeMillis();
		// 1.获取连接
        conn = JDBCUtils.getConnection();
        
        // 2.创建statement对象
        ps = conn.createStatement();

        for(int i = 1 ; i <= 20000 ; i++) {
            String sql = "insert into goods(name)values("+ "name_" + i +")";

            //1. "攒" sql
            ps.addBatch(sql);

            if(i % 500 == 0) {

                //2.  攒够500,执行一次batch
                ps.executeBatch();
                
                //3. 提交
                conn.commit();
            }
        }

        long end = System.currentTimeMillis();

        System.out.println("花费的时间为:" + (end - start));

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

2.PreparedStatement 批处理写入

@Test
public void testInsert2() {

    Connection conn = null;
    PreparedStatement ps = null;
    try {
        // 关闭自动提交
        conn.setAutoCommit(false);

        long start = System.currentTimeMillis();
		// 1.获取连接
        conn = JDBCUtils.getConnection();
        
        // 2.创建prepareStatement对象
        String sql = "insert into goods(name)values(?)";
        ps = conn.prepareStatement(sql);

        for(int i = 1 ; i <= 20000 ; i++) {
            ps.setObject(1, "name_" + i);	//代表设置给第一个?号位置的值为Object类型

            //1. "攒" sql
            ps.addBatch();

            if(i % 500 == 0) {

                //2.  攒够500,执行一次batch
                ps.executeBatch();
                
                //3. 提交
                conn.commit();

                //4. 清空batch
                ps.clearBatch();
            }
        }

        long end = System.currentTimeMillis();

        System.out.println("花费的时间为:" + (end - start));

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3.Statement 和 PreparedStatement 关系和区别

Statement 和 PreparedStatement之间的关系和区别.
关系:PreparedStatement继承自Statement,都是接口
区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高

如何选择使用 Statement 和 PreparedStatement 对象

JDBC驱动的最佳化是基于使用的是什么功能. 选择PreparedStatement还是Statement取决于你要怎么使用它们. 对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的.

PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行

Statement对象:
用于执行不带参数的简单SQL语句;
特点:
a. 只执行单条的sql语句;
b. 只能执行不带参数的sql语句;
c.运行原理的角度,数据库接收到sql语句后需要对该条sql语句进行编译后才执行;
d.与其它接口对比,适合执行单条且不带参数的sql语句,这种情况执行效率相对较高。

PreparedStatement对象
执行带或不带 IN 参数的预编译 SQL 语句;
特点:
a. 继承自Statement接口(意味着功能相对更加全面);
b. 带有预编译的特性;
c. 批量处理sql语句;
d. 处理带未知参数的sql语句;
e. 具有安全性,即可以防止恶意的sql语句注入攻击;
f. 在处理单条语句上,执行效率没有Statement快;
g. 提高程序的可读性和可维护性。


执行效率(如果都是在数据库表中插入10000条记录情况下):

1.使用Statement对象 用时31秒
2.预编译PreparedStatement 用时14秒
3.使用PreparedStatement + 批处理 用时485毫秒

1.使用Statement对象
使用范围:当执行相似SQL(结构相同,具体值不同)语句的次数比较少
优点:语法简单
缺点:采用硬编码效率低,安全性较差。
原理:硬编码,每次执行时相似SQL都会进行编译

public void exec(Connection conn){
    try {
        Long beginTime = System.currentTimeMillis();
        conn.setAutoCommit(false);//设置手动提交
        Statement st = conn.createStatement();
        for(int i=0;i<10000;i++){
            String sql="insert into t1(id) values ("+i+")";
            st.executeUpdate(sql);
        }
        Long endTime = System.currentTimeMillis();
        System.out.println("Statement用时:"+(endTime-beginTime)/1000+"秒");//计算时间
        st.close();
        conn.close();
    } catch (SQLException e) {             
        e.printStackTrace();
    }
}

执行时间:Statement用时:31秒

2.预编译PreparedStatement
使用范围:当执行相似sql语句的次数比较多(例如用户登陆,对表频繁操作…)语句一样,只是具体的值不一样,被称为动态SQL
优点:语句只编译一次,减少编译次数。提高了安全性(阻止了SQL注入)
缺点: 执行非相似SQL语句时,速度较慢。
原理:相似SQL只编译一次,减少编译次数
事例执行过程:

public void exec2(Connection conn){
    try {
        Long beginTime = System.currentTimeMillis();
        conn.setAutoCommit(false);//手动提交
        PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)");
        for(int i=0;i<10000;i++){
            pst.setInt(1, i);
            pst.execute();   
        }
        conn.commit();
        Long endTime = System.currentTimeMillis();
        System.out.println("Pst用时:"+(endTime-beginTime)+"秒");//计算时间
        pst.close();
        conn.close();
    } catch (SQLException e) {               
        e.printStackTrace();
    }
}

执行时间:Pst用时:14秒

3.使用PreparedStatement + 批处理
使用范围:一次需要更新数据库表多条记录
优点:减少和SQL引擎交互的次数,再次提高效率,相似语句只编译一次,减少编译次数。提高了安全性(阻止了SQL注入)
缺点:
原理:批处理: 减少和SQL引擎交互的次数,一次传递给SQL引擎多条SQL。
名词解释:
PL/SQL引擎:在oracle中执行pl/sql代码的引擎,在执行中发现标准的sql会交给sql引擎进行处理。
SQL引擎:执行标准sql的引擎。
事例执行过程:

public void exec3(Connection conn){
     try {
           conn.setAutoCommit(false);
           Long beginTime = System.currentTimeMillis();
           PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)");
 
          for(int i=1;i<=10000;i++){   
                pst.setInt(1, i);
                pst.addBatch();//加入批处理,进行打包
                if(i%1000==0){//可以设置不同的大小;如50,100,500,1000等等
                      pst.executeBatch();
                      conn.commit();
                      pst.clearBatch();
                }//end of if
           }//end of for
           pst.executeBatch();
           Long endTime = System.currentTimeMillis();
           System.out.println("pst+batch用时:"+(endTime-beginTime)+"毫秒");
           pst.close();
           conn.close();
      } catch (SQLException e) {
            e.printStackTrace();
      }
}

执行时间:pst+batch用时:485毫秒

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值