1.簡單,實用,高效的 分段Batch 提交方法
其實C3P0你直接可以理解爲JDBC,只是封裝了一下下而已,但封裝了一下下就好用多了哦,首先說一下 我這邊的數據量實在千萬級的,提高效率的方法有很多的,當然這邊寫的方法 是我認爲 在再用JAVA簡單控制不同數據庫的情況下能控制效率的最好辦法了(下面的代碼都是我經過實踐出來的,我基本上把網上所有的方法都跑了一遍 目前覺得這樣寫法效率最高,請注意看註釋!!!!)首先貼上一段寫法代碼如下:
//參數集 static int COUNT = 0; // 負責統計提交數 static Connection conn = null; static Connection conn1 = null; static ResultSet rs = null; static PreparedStatement pstmt = null; static PreparedStatement pstmt1 = null; static PreparedStatement mySelect = null; static int ALLCOUNT = 0; static int SELECTCIUNT = 0; // 查詢條數 public static void INSERT_EMP()throws Exception { conn = DBManager.getConnection();//從庫 conn1 = DBManager.getConnection1();//主庫 conn1.setAutoCommit(false);//設置手動提交 try { pstmt = conn.prepareStatement("SELECT *FROM EMP");//假如有1000W數據 rs = pstmt.executeQuery(); //查詢數據,執行了這句纔是進數據庫查 pstmt1= conn1.prepareStatement("INSERT INTO EMP VALUES(?,?,?,?,?)"); int insertCount=0;//插入的條數 while (rs.next()) { SELECTCIUNT++; pstmt1.setString(1, rs.getString(1)); pstmt1.setString(2, rs.getString(2)); pstmt1.setString(3, rs.getString(3)); pstmt1.setString(4, rs.getString(4)); pstmt1.setTimestamp(5, Update_Time); insertCount+=pstmt1.getFetchSize();//可以獲得SET到pstmt1裏面的參數的個數 COUNT++; ALLCOUNT++; pstmt1.addBatch();//把所有查出來的數據set到pstmt1裏面(你可以理解它爲一個集合),但沒有提交哦~只是放在pstmt1裏面。 if(COUNT==100000){//當循環10W次的提交一次 pstmt1.executeBatch();//這纔是向數據庫發送語句 conn1.commit();//提交一下下 COUNT=0;//把循環次數設爲0 pstmt1= conn1.prepareStatement(Insert_MySql_V_R_I_001);//這句話不要遺漏,不然會導致只能插入1OW條。 pstmt1.clearBatch(); //清除pstmt1裏面所有的值。 } } //這3行別忘了寫 pstmt1.executeBatch(); conn1.commit(); pstmt1.clearBatch(); } catch (SQLException e) { conn1.rollback(); } finally{ attemptClose(rs); attemptClose(pstmt); attemptClose(pstmt1); attemptClose(conn); attemptClose(conn1); } } //下面3個是簡單封裝的關閉 static void attemptClose(ResultSet o) { try { if (o != null) o.close(); } catch (Exception e) { e.printStackTrace(); } } static void attemptClose(Statement o) { try { if (o != null) o.close(); } catch (Exception e) { e.printStackTrace(); } } static void attemptClose(Connection o) { try { if (o != null) o.close(); } catch (Exception e) { e.printStackTrace(); } } }
以上的代碼有幾點我簡單說明一下
簡單注意點:
(1).conn.setAutoCommit(false);//設置(false)手動提交 (true) 是自動提交 不寫是默認自動提交,有啥區別捏?
以寡人一百年的編程經驗覺得 就是在你INSERT數據的時候,設置了(false) 那麼你插100條 如果插到50條的時候出錯了,那麼你前面插 得 就不會插到數據庫中,因爲你手動控制事務的,就是我代碼裏面最後才commit的。當然如果是(true) 50條的出錯之前插的數據就還在數據庫中,這樣會造成插一點,留一點 專業的稱呼 叫 《 髒數據》(哎~就是沒插乾淨偷笑)
(2).爲什麼用prepareStatement 而不用statement?
之間的效率我自己也測試過,大數據量的情況下確實有很大的差距,簡単說一下我對着倆鳥的理解 一般菜鳥面試的時候會被問到哦 你可以這樣回答它們prepareStatement 比statement快,因爲prepareStatement是預編譯的,(預編譯可以理解爲--軟解碼:數據庫有個緩存策略,就是把以前執行過的SQL已 <K,V>的形式保存起來, 下次再來執行,不需要編譯直接找對應的V ,就是從緩存中找到已被編譯過的語句然後直接就執行了。當然也得說一下硬解碼,媽的其實硬解碼就是發一次 就--語法檢查--什麼什麼的--權限檢查--編譯)明白了吧?哇哈哈~而prepareStatement 恰恰就是軟解碼的 所以快。所以在執行多條Sql的時候就用prepareStatement,但如果就執行一次Sql的話就用statement 。還有就是第一次用prepareStatement有點慢,要添加到緩存中的嘛(大家第一次都是這樣的 以後就好了)。
(3).肯定有人在糾結一個問題...就是用不用List?
應該這樣說:是查一點插一點快呢?還是全查出來放List裏面再插到數據庫中快呢? 其實這和數據庫的緩存設置也有點關係的,當然倆個方法我都實驗過,但有一個小問題啊,就是數據量太大 你放到list中會報內存溢出(list網上說可以放8G 內存定的,俺沒試過哦~這叫俺咋試),有人說放一點清一點 ,那這還不 是分段嘛 , 上面我也說了上面的 pstmt1 和list在這實現的效果一樣。所以最後用了上述方法。
我這邊比較複雜的SQL一般50W條300多秒這樣。希望給你得到幫助~