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(); } } }
以上的代码有几点我简单说明一下
原理:很简单 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).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多秒这样。希望给你得到帮助~