java数据库批量插入数据

jdbc知识介绍

|-- Statement
    -- PreparedStatement  子接口,建议使用,会对sql语句先进行编译再给数据库
PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。
当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。
               
批处理相关方法
void addBatch(String sql)  添加批处理   
void clearBatch()      清空批处理
int[] executeBatch()    执行批处理   

事务提交
con.setAutoCommit(false);     默认自动提交,在这里需要设置为false,手动提交
con.commit();  
con.rollback();
        
3.常见问题
批量处理无法生效        
1、rewriteBatchedStatements=true
 

代码演示

1普通插入方式

10万条数据,耗时15秒

private String url = "jdbc:mysql://localhost:3306/test01";
  private String user = "root";
  private String password = "123456";
  @Test
  public void Test(){
    Connection conn = null;
    PreparedStatement pstm =null;
    ResultSet rt = null;
    try {
      Class.forName("com.mysql.jdbc.Driver");
      conn = DriverManager.getConnection(url, user, password);   
      String sql = "INSERT INTO myTable values(?,?)";
      pstm = conn.prepareStatement(sql);
      Long startTime = System.currentTimeMillis();
      for (int i = 1; i <= 100000; i++) {
          pstm.setInt(1, i);
          pstm.setInt(2, i);
          pstm.executeUpdate();
      }
      Long endTime = System.currentTimeMillis();
      System.out.println("用时:" + (endTime - startTime));
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }finally{
      if(pstm!=null){
        try {
          pstm.close();
        } catch (SQLException e) {
          e.printStackTrace();
          throw new RuntimeException(e);
        }
      }
      if(conn!=null){
        try {
          conn.close();
        } catch (SQLException e) {
          e.printStackTrace();
          throw new RuntimeException(e);
        }
      }
    }
  }

2使用batch

注意更改url = “jdbc:mysql://localhost:3306/test01?rewriteBatchedStatements=true”;
pstm.addBatch();代替pstm.executeUpdate();
最后批量操作pstm.executeBatch();

10万条数据,耗时4秒

 private String url = "jdbc:mysql://localhost:3306/test01?rewriteBatchedStatements=true";
    private String user = "root";
    private String password = "123456";

    @Test
    public void Test() {
        Connection conn = null;
        PreparedStatement pstm = null;
        ResultSet rt = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, user, password);
            String sql = "INSERT INTO myTable values(?,?)";
            pstm = conn.prepareStatement(sql);
            Long startTime = System.currentTimeMillis();
            conn.setAutoCommit(false);
            for (int i = 1; i <= 100000; i++) {
                pstm.setInt(1, i);
                pstm.setInt(2, i);
                //1w提交一次
                pstat.addBatch();
                if (i % 10000 == 0) {
                    pstat.executeBatch();
                    pstat.clearBatch();
                }
            }
            //提交余下部分
            pstat.executeBatch(); //执行批处理
            pstat.clearBatch();  //清空批处理
            con.commit();
            Long endTime = System.currentTimeMillis();
            System.out.println("用时:" + (endTime - startTime));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (pstm != null) {
                try {
                    pstm.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }
    }

Mybatis方式


    insert into student (  ) 
    values 
    
        (null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})
    

参数解释:
collection:指定要遍历的集合;
表示传入过来的参数的数据类型。该参数为必选。要做 foreach 的对象,作为入参时,List 对象默认用 list 代替作为键,数组对象有 array 代替作为键,Map 对象没有默认的键
item:将当前遍历出的元素赋值给指定的变量,然后用#{变量名},就能取出变量的值,也就是当前遍历出的元素
separator:每个元素之间的分隔符, select * from Emp where id in(1,2,3)相当于1,2,3之间的","
Index:索引,遍历list的时候index就是索引,遍历map的时候index表示的就是map的key,item就是map的值.
 

特别注意:mysql默认接受sql的大小是1048576(1M),即第三种方式若数据量超过1M会报如下异常:(可通过调整MySQL安装目录下的my.ini文件中[mysqld]段的"max_allowed_packet = 1M")

mybatis的 ExecutorType.BATCH


Mybatis内置的ExecutorType有3种,默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优; 但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的。
 

 

你可能感兴趣的:(数据库)