有一业务场景, 需要初始化所有员工本月的考勤台账. 基本流程是删掉原来的数据 -- >然后重新插入--> 插入月统计表数据 当时场景900员工, 一个月算30天, 一次初始化要插入2.7W数据.如果dao层框架insert. 要差不多40s. 所以用jdbc进行批量操作
public void initMonth(){
deleteOld(); //删除原来的数据
final String sql = "insert into AttendanceUserDay(id,userId,date,remark) " +
" values(?,?,?,?)";
Session session = this.sqlDao.getHibernateTemplate().getSessionFactory().openSession();
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
System.out.println(connection.getAutoCommit());
PreparedStatement ps = connection.prepareStatement(sql);
for(int i = 0; i < newObjList.size() ; i++ ){
AttendanceUserDay obj = newObjList.get(i);
ps.setString(1, obj.getId());
ps.setString(2, obj.getUserId());
ps.setDate(4, new java.sql.Date (obj.getDate().getTime()));
ps.setString(6, obj.getRemark());
ps.addBatch();
if(i > 0 && i % 1000 == 0){ //每满1000条执行插入一次
System.out.println("executeBatch : "+ i);
ps.executeBatch();
ps.clearBatch();
}
}
ps.executeBatch();
}
});
//计算并插入月考勤统计表数据....
}
该业务方法涉及多表操作,如果自己进行commit会比较麻烦, 系统使用了Spring.故该业务方法的事务由Spring管理了.
测试的时候发现出现阻塞.一直插入不了数据. 排查发现是这里的锅.
Session session = this.sqlDao.getHibernateTemplate().getSessionFactory().openSession();
hibernate的openSession是开启一个新的对话.那么和前面deleteOld()的session是不同一个,而且因为事务给spring管理. deleteOld方法执行后没有提交事务, 这边又起了另外一个session.对同一张表操作.阻塞了.
所以应该使用getCurrentSession.获取当前的session进行操作
Session session = attendanceUserDayDao.getHibernateTemplate().getSessionFactory()
.getCurrentSession();
也可以使用jdbcTemplate进行批量插入, 原理一样