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 id="insertBatch" >
    insert into student ( <include refid="Base_Column_List" /> ) 
    values 
    <foreach collection="list" item="item" index="index" separator=",">
        (null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})
    </foreach>
</insert>

參數解釋:
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,這在某型情形下是不符合業務要求的。
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章