当前项目代码
公司开发框架的orm层采用的hibernate,普通查询和少量的数据插入,一直能满足要求,但是对于大批量的数据入库,使用hibernate就显得很慢。之前项目代码中一直是采用的hibernate官方建议的办法,当save到一定数量,及时的flush和clear。
public static void main(String[] args) {
long time1 = System.currentTimeMillis();
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
for (int i = 1; i <= 100000; i++) {
Student student = new Student();
student.setName("hero" + i);
student.setBirthDate(new Timestamp(System.currentTimeMillis()));
student.setJoinDate(new Date());
student.setEmail(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(1000)));
session.save(student);
if (i % 100 == 0) {
session.flush();
session.clear();
}
}
session.getTransaction().commit();
session.close();
sessionFactory.close();
System.out.println("一共耗时:"+(System.currentTimeMillis()-time1)/1000);
}
100000条数据入库时间:
一共耗时:18
通过抓包可以发现,每个对象都执行了一条insert语句。一般数据库都支持批量插入,hibernate有无办法支持呢?
优化
由于我们的项目使用mysql,这里的优化主要是在jdbc的URL里面追加参数:rewriteBatchedStatements=true,并且hibernate的参数hibernate.jdbc.batch_size设置合适的值。
这个参数是开启mysql批处理的。
原url:
jdbc:mysql://127.0.0.1:3306/hy_hero?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
现在url:
jdbc:mysql://127.0.0.1:3306/hy_hero?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
添加了rewriteBatchedStatements=true后,同样的100000条数据,入库时间缩短为8秒,性能提升超过一倍。
通过抓包,可以看到已经是使用的批量插入
备注
上述的案例只是在我本机写的一个简单的demo,所使用的都是我本机的数据库,看上去10万条数据入库速度只提升了一倍。在实际生产环境中,提升效果远远超出本机测试。