用jdbc代替hibernate处理大批量的关联数据更新
在Spring+hibernate大批量数据处理描述了可以用hibernate快速的处理大批量数据更新:
14.2. 批量更新(Batch updates)
此方法同样适用于检索和更新数据。此外,在进行会返回很多行数据的查询时, 你需要使用 scroll() 方法以便充分利用服务器端游标所带来的好处。
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); ScrollableResults customers = session.getNamedQuery("GetCustomers") .setCacheMode(CacheMode.IGNORE) .scroll(ScrollMode.FORWARD_ONLY); int count=0; while ( customers.next() ) { Customer customer = (Customer) customers.get(0); customer.updateStuff(...); if ( ++count % 20 == 0 ) { //flush a batch of updates and release memory: session.flush(); session.clear(); } } tx.commit(); session.close(); 条件是: 1,将JDBC的批量抓取数量(batch size)参数设置到一个合适值 (其实是500——1000比较合适): hibernate.jdbc.batch_size 202,在执行批量处理时关闭二级缓存:
hibernate.cache.use_second_level_cache false
但是要是在做了上述操作后,还需要对这些记录关联的另外一个表的记录做一个更新,那用hibernate是有问题的。 因为Hibernate更新一条记录的时候必须首先load查出这条记录,那在批量更新的时候不是很耗费性能?确实是这样的。 所以,在大批量处理更新一个大型数据集合,并且需要修改这个集合关联的数据库表对象时,还是需要JDBC来解决问题。如:
Connection conn1 = this.getConnection();
PreparedStatement pstmt1 = null;
ResultSet rs1 = null;
String strsql1 = "select workitem_id,work_sheet_no,process_code,process_name,process_ins_id,"
+"activity_code,activity_name,zone_code,activity_role,run_mode,pre_activity_code,"
+"pre_activity_name,sendor,sendor_name,participant,participant_name,approve_note,"
+"start_time,end_time,time_limit,time_limit_unit,over_time,reassign_participant_id,"
+"form_type,form_id,app_name,urge_date,urger,last_date,last_count,untread,state,remark,"
+"activity_role_id from wf_workitem r where r.process_code='ec_reprints_invoice_process'";
Connection conn2 = this.getConnection2();
PreparedStatement pstmt2 = null;
String strsql2 = "insert into os_currentstep(id,entry_id,step_id,action_id,owner,start_date,"
+"finish_date,due_date,status,caller) values(seq_os_currentsteps.nextval,?,?,?,?,?,?,?,?,?)";
int updateNum=0;
try {
pstmt1 = conn1.prepareStatement(strsql1);
pstmt1.setFetchSize(1000);
pstmt2 = conn2.prepareStatement(strsql2);
rs1 = pstmt1.executeQuery();
int i=0;
while (rs1.next()) {
i++;
String process_ins_id = rs1.getString("process_ins_id");
String idsub=process_ins_id.substring(process_ins_id.indexOf("/", 1));
pstmt2.setObject(1, idsub.substring(1,idsub.indexOf("/", 1)));
pstmt2.setObject(2, getStepIdByStepName(rs1.getString("activity_name"),rs1.getString("process_code")));
pstmt2.setNull(3,Types.INTEGER);
pstmt2.setObject(4, rs1.getString("activity_role"));
Date d=convertStringToDate("yyyy-MM-dd HH:mm:ss", rs1.getString("start_time"));
if(d==null){
pstmt2.setNull(5,Types.DATE);
}else{
pstmt2.setObject(5, new java.sql.Timestamp(d.getTime()));
}
pstmt2.setNull(6,Types.DATE);
pstmt2.setNull(7,Types.DATE);
if(rs1.getString("participant")==null){
pstmt2.setObject(8,"Queued");
}else{
pstmt2.setObject(8,"Underway");
}
pstmt2.setObject(9, rs1.getString("participant"));
pstmt2.addBatch();
if(i%500==0){
updateNum=updateNum+pstmt2.executeBatch().length;
}
}
updateNum=updateNum+pstmt2.executeBatch().length;
System.out.println("更新了当前待办记录条数:"+updateNum);
} catch (Exception e) {
e.printStackTrace();
} finally {
cleanConn(conn1,pstmt1,rs1);
cleanConn(conn2,pstmt2,null);
}