1. 程式人生 > >JDBC批量插入

JDBC批量插入

最近專案中有用到JDBC技術,存在大量資料要進行插入,通過研究採用批量插入速度快的不是一點點。下面簡單比較了一下普通插入與批量插入5W條資料的時間效率。

常規插入:耗時12952ms

public static void normalInsert() throws SQLException {
    long start = System.currentTimeMillis();
    Connection conn = getConnection();
    PreparedStatement ps = null;
    for (int i=0;i < 50000;i++){
        String sql = "insert into xxx values (?,'1','1')";
        ps = conn.prepareStatement(sql);
        ps.setString(1, i+"");
        ps.execute();
        ps.close();
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
}

批量插入:耗時930ms

public static void batchInsert() throws SQLException {
    long start = System.currentTimeMillis();
    Connection conn = getConnection();
    conn.setAutoCommit(false);
    PreparedStatement ps = null;
    String sql = "insert into xxx values (?,'1','1')";
    ps = conn.prepareStatement(sql); // 批量插入時ps物件必須放到for迴圈外面
    for (int i=0;i < 50000;i++){
        ps.setString(1, i+"");
        ps.addBatch();
        // 每1000條記錄插入一次
        if (i % 1000 == 0){
            ps.executeBatch();
            conn.commit();
            ps.clearBatch();
        }
    }
    // 剩餘數量不足1000
    ps.executeBatch();
    conn.commit();
    ps.clearBatch();
    long end = System.currentTimeMillis();
    System.out.println(end - start);
}

顯而易見,這還是表結構簡單,插入資料就相差十倍多。

oracle插入150W耗時3分鐘;刪除52秒。
truncate清空表,速度超快;delete刪除比較慢,可以加條件;刪除150w資料truncate只要2秒,而delete可能要差不多1分鐘
truncate table xxx;    delete from xxx;

常見SQL錯誤:

1)Oracle資料庫中開啟的遊標最大數為一定值,預設情況下是300,當代碼到第二步時,迴圈中一個PreparedStatement佔用了一個數據庫遊標,執行的迴圈超過這個數時就會產生遊標數目溢位錯誤。
解決辦法:每次執行完PreparedStatement,都將PreparedStatement.close()下,釋放掉這個資源就好了
Exception in thread "main" java.sql.SQLException: ORA-00604: 遞迴 SQL 級別 1 出現錯誤
ORA-01000: 超出開啟遊標的最大數
ORA-00604: 遞迴 SQL 級別 1 出現錯誤
ORA-01000: 超出開啟遊標的最大數

ORA-01000: 超出開啟遊標的最大數

2)java.sql.SQLException:ORA-00054;資源正忙,但指定以NOWAIT方式獲取資源,或者超時失敗
原因:資料庫中存在未提交的記錄

3)java.sql.SQLException 索引中丟失in或out引數
原因:SQL語句有問題
解決:jdbc進行欄位拼接插入操作時,為string型別的加上單引號
          另外,用prepareStatement.setString(1, 欄位值),可以防止欄位值有單引號而破壞sql問題

4)java.sql.BathUpdateException:ORA-01461;僅能繫結要插入LONG列的LONG值
原因:由於要插入的欄位長度超出了資料庫中表定義的欄位長度
--------------------------補充-----------------------------------
varchar2是Oracle提供的特定資料型別
varchar2(10)一般情況最多存5個漢字,10個字元。具體要看資料庫使用的字符集:GBK(漢字2位元組;英文1個;Oracle安裝預設GBK編碼格式);UTF-8(漢字3位元組,英文1個)
一般頁面做輸入字串長度校驗時,以資料庫設計欄位最大長度/3作為最大長度
nvarchar(10)可以存10個漢字,10個字元
當長度大於4000的時候就應該用CLOB,因為oracle的varchar2最多4000個字元

5)ORA-24816:在實際的LONG或LOB列之後提供了擴充套件的非LONG繫結資料
原因:這個問題很奇怪,就算沒有LONG型別的資料,全部都是VARCHAR2和CLOB在操作資料庫更新的時候一直報這個錯誤
解決:歪打正著,調整了一下各種更新欄位位置,將放在前面的CLOB型別放在後面,就不報錯了