Spring Boot JPA saveAll() 插入到数据库的速度非常慢



我正在使用Spring Boot和Hibernate为一个简单的Web应用程序创建RESTful API,在那里我读取一个.csv文件并将每一行插入到mysql数据库表中。我能够成功 这样做,但任何大型 CSV 文件都需要很长时间。我知道最好对我的插入语句进行批处理以减少数量 的交易,但我认为我不会用我拥有的当前代码做到这一点。这是我目前正在做的事情(有效但非常慢(:

CsvUploaderController.java

public class CsvUploaderController {
// CsvUploader Repository definition:
// @Repository
// public interface CsvUploaderRepository extends JpaRepository<CityObj, Integer>
@Autowired
CsvUploaderRepository csvUploaderRepository;
// gets called by front end with the .csv file data
@PutMapping("/upload_csv")
public List<CityObj> uploadCsv(@RequestBody Object data) {
// unpackCSV converts an arrayList of Objects to a List of CityObj
List<CityObj> unpackedCSV = unpackCSV((ArrayList<Object>) data);
csvUploaderRepository.deleteAll(); // delete all rows in table currently. Not sure if this is relevent to issue
// save all items as rows in my database
return csvUploaderRepository.saveAll(unpackedCSV); // this is where it takes forever to complete
}
...
}

应用程序属性:

spring.datasource.url=jdbc:mysql://url.to.my.database
spring.datasource.username=myusername
spring.datasource.password=weirdpassword
spring.datasource.hikari.maximumPoolSize = 5
spring.jpa.properties.hibernate.generate_statistics=true 
spring.jpa.properties.hibernate.jdbc.batch_size=20 // I've tried playing around with different values. Hasnt helped
#spring.jpa.properties.hibernate.order_inserts=true // I've also tried using this but not sure what it does and didnt help

我做错了什么?如何提高刀片的性能?我是否理解不正确 saveAll((?我的问题与这里描述的非常相似: 弹簧启动 2 升级 - 弹簧启动数据 jpa saveAll(( 非常慢

使用 JdbcTemplate,它要快得多。

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
public int[] batchInsert(List<Book> books) {
return this.jdbcTemplate.batchUpdate(
"insert into books (name, price) values(?,?)",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, books.get(i).getName());
ps.setBigDecimal(2, books.get(i).getPrice());
}
public int getBatchSize() {
return books.size();
}
});
}

您可以通过调整MySQL的HikariCP配置来获得一些性能: https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration

由于saveAll()内部只是循环列表,因此您可以手动执行循环并每 20 个实体刷新一次,以减少持久性上下文的压力。

正确完成批处理当然会有所帮助。

最后,最快的方法是具有JdbcTemplate和多值插入的普通 SQL,例如:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

最新更新