以下是JDBC批处理的例子,还有处理数据的一些总结。(在公司把MySql数据库几千万的数据导入搜索Elasticsearch里面)
一、功能描述
二、细节考虑
2.1 为什么使用PreparedStatement进行处理?
1、PreparedStatement接口继承Statement,PreparedStatement实例包含已编译的SQL语句,所以其执行速度要快于Statement 对象。
2、PreparedStatement支持占位符,提高了安全性,它防止了sql语句的注入(实际处理数据时候,如果商品名称有单引号,不使用PreparedSatement会报错!)
3、PreparedStatement代码的可读性和可维护性较好.
2.2 分页查询和Result游标进行查询有什么区别?
分页查询是每次去数据库查询一批结果回来,进行处理,如此循环,每次循环都要建立数据库连接;Result游标也是每次去数据库取一部分结果回来(Oracle默认是10条,MySql也支持),但是只需要打开一个连接,持续使用;如果数据量很大,通信速度很快,使用游标进行数据查询。
2.3 MySql JDBC怎么实现Result游标?
1、当statement设置以下属性时,采用的是流数据接收方式,每次只从服务器接收部份数据,直到所有数据处理完毕,不会发生JVM OOM。
setResultSetType(ResultSet.TYPE_FORWARD_ONLY);
setFetchSize(Integer.MIN_VALUE);
2、调用statement的enableStreamingResults方法,实际上enableStreamingResults方法内部封装的就是第1种方式。
3、设置连接属性useCursorFetch=true (5.0版驱动开始支持),statement以TYPE_FORWARD_ONLY打开,再设置fetch size参数,表示采用服务器端游标,每次从服务器取fetch_size条数据。
三、代码
地址:https://github.com/huangchanghuan/CouponsUtil
3.1 JDBC批处理MySql数据
public static long importData( ){ String url = "jdbc:mysql://192.168.0.183:3306/couponsdb?user=root&password=" + "Sunstar123!&useUnicode=true&characterEncoding=UTF-8"; String sql = "SELECT a.classid,a.spname,a.sppic,0,0,1,b.value_id,a.id FROM " + "ss_hj_search_result a LEFT JOIN ss_hj_value b ON (a.brand_name = b.value_name " + "AND b.quantity_id = 1) WHERE a.id not in (select autoid from ss_hj_product_relation)"; try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } long allStart = System.currentTimeMillis(); long count =0; Connection con = null; Connection con1 = null; PreparedStatement psHJSearchResult = null; PreparedStatement psHJProduct = null; PreparedStatement psHJProductPicture = null; PreparedStatement psHJProductRelation = null; ResultSet rs = null; int productId=572457; int pictureId=1711669; int relationId=252381; try { //查询操作创建连接(这个连接单独用来查询,游标需要保持连接不断开) con = DriverManager.getConnection(url); con.setAutoCommit(false); psHJSearchResult = con.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); psHJSearchResult.setFetchSize(1); psHJSearchResult.setFetchDirection(ResultSet.FETCH_REVERSE); rs = psHJSearchResult.executeQuery(); // 写入操作创建连接 con1 = DriverManager.getConnection(url); con1.setAutoCommit(false); //插入ss_hj_product psHJProduct = con1.prepareStatement("insert into ss_hj_product" + "(PRODUCT_ID,CLS_ID,PRODUCT_NAME,MAIN_PICTURE,SALES_VOLUME," + "COMMENTS_NUMBER,STS,PRIORITY,BRAND_ID) values(?,?,?,?,?,?,?,?,?)"); //插入ss_hj_product_picture psHJProductPicture = con1.prepareStatement("insert into ss_hj_product_picture" + "(PRODUCT_ID,PRODUCT_URL,PRODUCT_VIEW_URL,PICTURE_ID) values(?,?,?,?)"); //插入ss_hj_product_relation psHJProductRelation = con1.prepareStatement("insert into ss_hj_product_relation" + "(PRODUCT_ID,AUTOID,RELATION_ID) values(?,?,?)"); while (rs.next()) { //聚合商品表 psHJProduct.setInt(1,productId); psHJProduct.setInt(2,rs.getInt("classid")); psHJProduct.setString(3,rs.getString("spname")); psHJProduct.setString(4,rs.getString("sppic")); psHJProduct.setInt(5,0); psHJProduct.setInt(6,0); psHJProduct.setInt(7,1); psHJProduct.setInt(8,productId); psHJProduct.setInt(9,rs.getInt("value_id")); psHJProduct.addBatch(); //图片表 psHJProductPicture.setInt(1,productId); psHJProductPicture.setString(2,rs.getString("sppic")); psHJProductPicture.setString(3,rs.getString("sppic")); psHJProductPicture.setInt(4,pictureId); psHJProductPicture.addBatch(); //关系表 psHJProductRelation.setInt(1,productId); psHJProductRelation.setInt(2,rs.getInt("id")); psHJProductRelation.setInt(3,relationId); psHJProductRelation.addBatch(); //id增加 productId++; pictureId++; relationId++; count++; if(count%100000==0) {//提交 psHJProduct.executeBatch(); psHJProductPicture.executeBatch(); psHJProductRelation.executeBatch(); con1.commit(); } } //最后一批没有提交处理 psHJProduct.executeBatch(); psHJProductPicture.executeBatch(); psHJProductRelation.executeBatch(); con1.commit(); } catch (Exception e) { logger.error("异常"); e.printStackTrace(); } finally { logger.error("=productId:"+productId); logger.error("=pictureId:"+pictureId); logger.error("=relationId:"+relationId); try { if(rs!=null){ rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(psHJSearchResult!=null){ psHJSearchResult.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(con!=null){ con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return count; }
3.2 JDBC批处理和ES Java Client批处理数据
四、总结
1.JDBC要配置编码格式,不然可能出现乱码;
2.因为数大数据量处理,编码时候注意JVM的GC回收;
3.使用PreparedStatement处理数据;