我试图用大量的测试数据填充我的数据库,所以我写了一个CommandLineRunner来保存大约2k个实体。
它的工作-但它需要永远完成(5-10分钟)-我处理的方式错了吗?
@Component
public class DbSeederTest implements CommandLineRunner {
@Autowired
FirstRepo firstRepo;
@Autowired
SecondRepo secondRepo;
@Autowired
ThirdRepo thirdRepo;
private List<FirstEnt> firstList = new ArrayList<>();
private List<SecondEnt> secondList = new ArrayList<>();
private List<ThirdEnt> thirdList = new ArrayList<>();
private void generateTestData() {
// generate alot of entities, and add them to the Lists
}
@Override
public void run(String... args) throws Exception {
System.out.println("saving ents...");
generateTestData();
try {
firstRepo.save(firstList);
secondRepo.save(secondList);
thirdRepo.save(thirdList);
} catch(Exception e) {
e.printStackTrace();
}
}
}发布于 2017-02-15 20:11:22
您可以尝试利用大容量插入特性。
您可以将hibernate属性定义为hibernate的SessionFactory属性之一
<property name="jdbc.batch_size">250</property>使用此批处理设置,您应该有如下输出:
insert into Table(id , name) values (1, 'na1') , (2, 'na2') ,(3, 'na3').。
而不是
insert into Table(id , name) values (1, 'na1');
insert into Table(id , name) values (2, 'na2');
insert into Table(id , name) values (3, 'na3');在您的存储库保存方法中,您将持久化大约250个实体(您必须做一些测试,在您的应用程序中性能最佳的点是什么)。然后刷新会话以获得最佳性能,直到保存完所有数据:
public void save(List<Item> itemList){
for ( int i=0; i<itemList.size(); i++ ) {
session.save(itemList.get(i));
if ( i % 250 == 0 ) { //250, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
}发布于 2017-02-15 20:22:46
您可以通过使用线程概念来减少所需的时间。
在调用所有存储库的save方法之前,您拥有调用generateTestData();之后的数据。
所以稍微修改一下代码
Thread thread1 = new Thread(()->firstRepo.save(firstList));
Thread thread2 = new Thread(()->secondRepo.save(secondList));
Thread thread3 = new Thread(()->thirdRepo.save(thirdList));
thread1.start();
thread2.start();
thread3.start();使用Java8特性覆盖了Thread run方法。您可以在Java7中执行以下操作:
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
firstRepo.save(firstList);
}
});希望这能有所帮助。
https://stackoverflow.com/questions/42248732
复制相似问题