我正在尝试用大量的测试数据填充我的数据库,所以我写了一个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();
}
}
}
答案 0 :(得分:0)
您可以尝试利用批量插入功能。
你可以将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();
}
}
}
答案 1 :(得分:0)
您可以减少使用线程概念所花费的时间。
在调用所有回购的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();
使用Java 8功能覆盖Thread
run方法,您可以在Java 7中执行此操作,如下所示:
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
firstRepo.save(firstList);
}
});
希望这有帮助。