JDBC (C3P0)大批量數據的插入、更新實用方法。(實戰篇)-個人總結 1.簡單,實用,高效的 分段Batch 提交方法

1.簡單,實用,高效的 分段Batch 提交方法

             其實C3P0你直接可以理解爲JDBC,只是封裝了一下下而已,但封裝了一下下就好用多了哦,首先說一下  我這邊的數據量實在千萬級的,提高效率的方法有很多的,當然這邊寫的方法 是我認爲 在再用JAVA簡單控制不同數據庫的情況下能控制效率的最好辦法了(下面的代碼都是我經過實踐出來的,我基本上把網上所有的方法都跑了一遍 目前覺得這樣寫法效率最高,請注意看註釋!!!!)首先貼上一段寫法代碼如下:


  1. //參數集
  2. static int COUNT = 0; // 負責統計提交數
  3. static Connection conn = null;
  4. static Connection conn1 = null;
  5. static ResultSet rs = null;
  6. static PreparedStatement pstmt = null;
  7. static PreparedStatement pstmt1 = null;
  8. static PreparedStatement mySelect = null;
  9. static int ALLCOUNT = 0;
  10. static int SELECTCIUNT = 0; // 查詢條數
  11. public static void INSERT_EMP()throws Exception {
  12. conn = DBManager.getConnection();//從庫
  13. conn1 = DBManager.getConnection1();//主庫
  14. conn1.setAutoCommit(false);//設置手動提交
  15. try {
  16. pstmt = conn.prepareStatement("SELECT *FROM EMP");//假如有1000W數據
  17. rs = pstmt.executeQuery(); //查詢數據,執行了這句纔是進數據庫查
  18. pstmt1= conn1.prepareStatement("INSERT INTO EMP VALUES(?,?,?,?,?)");
  19. int insertCount=0;//插入的條數
  20. while (rs.next()) {
  21. SELECTCIUNT++;
  22. pstmt1.setString(1, rs.getString(1));
  23. pstmt1.setString(2, rs.getString(2));
  24. pstmt1.setString(3, rs.getString(3));
  25. pstmt1.setString(4, rs.getString(4));
  26. pstmt1.setTimestamp(5, Update_Time);
  27. insertCount+=pstmt1.getFetchSize();//可以獲得SET到pstmt1裏面的參數的個數
  28. COUNT++;
  29. ALLCOUNT++;
  30. pstmt1.addBatch();//把所有查出來的數據set到pstmt1裏面(你可以理解它爲一個集合),但沒有提交哦~只是放在pstmt1裏面。
  31. if(COUNT==100000){//當循環10W次的提交一次
  32. pstmt1.executeBatch();//這纔是向數據庫發送語句
  33. conn1.commit();//提交一下下
  34. COUNT=0;//把循環次數設爲0
  35. pstmt1= conn1.prepareStatement(Insert_MySql_V_R_I_001);//這句話不要遺漏,不然會導致只能插入1OW條。
  36. pstmt1.clearBatch(); //清除pstmt1裏面所有的值。
  37. }
  38. }
  39. //這3行別忘了寫
  40. pstmt1.executeBatch();
  41. conn1.commit();
  42. pstmt1.clearBatch();
  43. } catch (SQLException e) {
  44. conn1.rollback();
  45. } finally{
  46. attemptClose(rs);
  47. attemptClose(pstmt);
  48. attemptClose(pstmt1);
  49. attemptClose(conn);
  50. attemptClose(conn1);
  51. }
  52. }
  53. //下面3個是簡單封裝的關閉
  54. static void attemptClose(ResultSet o) {
  55. try {
  56. if (o != null)
  57. o.close();
  58. } catch (Exception e) {
  59. e.printStackTrace();
  60. }
  61. }
  62. static void attemptClose(Statement o) {
  63. try {
  64. if (o != null)
  65. o.close();
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. static void attemptClose(Connection o) {
  71. try {
  72. if (o != null)
  73. o.close();
  74. } catch (Exception e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. }

以上的代碼有幾點我簡單說明一下
             原理:很簡單 select 從庫 where ROWNUM=10000 INSERT INTO 主庫;(兩庫不在同一IP段)其實看註釋和代碼就能明白了
             簡單注意點:
(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多秒這樣。希望給你得到幫助~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章