JDBC (C3P0)大批量数据的插入、更新实用方法。(实战篇)-个人总结

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多秒这样。希望给你得到帮助~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值