我尝试使用spring-batch
进行批量/批量插入。
public ItemWriter<MyEntity> jpaItemWriter() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(ds);
builder.addAnnotatedClasses(MyEntity.class);
builder.setProperty("hibernate.show_sql", "true");
builder.setProperty("hibernate.batch_size", "20");
builder.setProperty("hibernate.order_updates", "true");
builder.setProperty("hibernate.order_inserts", "true");
HibernateItemWriter<MyEntity> writer = new HibernateItemWriter<>();
writer.setSessionFactory(builder.buildSessionFactory());
return writer;
}
结果:
我只收到单个insert
语句,而不是批量插入!我可以在postgresql级别的hibernate +日志中看到它。为什么批量插入不起作用?
更新
@Entity
public class MyEntity {
@Id
String shortname;
String fullname;
}
答案 0 :(得分:3)
Spring与SQL语句批处理无关,它全部由Hibernate管理。
我看到你已经启用了批处理并且配置正确,但这还不足以让它工作......你还需要使用正确的会话类型。在hibernate中有两种会话类型:有状态会话和无状态会话。
有状态会话,使用
sessionFactory.openSession();
并且在使用@Transactional时默认使用,从不使用批处理(即使已配置)并在事务提交时立即发送所有SQL语句。但是,您可以通过不时调用flush()来模拟批处理,并且SQL语句将在每次flush()时发送到db。
无状态会话,使用
获得sessionFactory.openStatelessSession();
尊重批处理配置,因此只需切换到无状态会话,批处理将按预期工作。 Hibernate将记录每个session.insert(),但不会将SQL insert语句发送到数据库,而是将SQL insert语句作为配置大小的批处理发送。所以它最好是&#34; tail -f&#34;数据库日志。 拥有两种会话类型的主要思想是,有状态会话使用缓存,并且每个保存的实体最终都在第一级缓存中,因此如果您保存100k实体,您将获得OOM。解决方案是使用无状态会话,该会话不与任何级别缓存交互。 您可以阅读有关stateless session。
的更多信息