如何解决如何使用 Java、Spring 启动读取包含 150K 记录的 excel 文件、验证、保留数据库中的行?
我有一个 Spring Boot 应用程序和一个 REST API 端点,它接收一个包含 15 万行和 5 列的 excel 文件。其中一些列是 Employee 表(sql server)的复合主键列的一部分
表员工: 员工 ID - varchar(20),名称- varchar(50),年龄 - smallint, Effective_date - 日期, expire_date - 日期, last_updated_ts - 时间戳, last_updated_by - varchar(20)
复合主键列:employeeId、name、age、effectiveDate
Excel 列:employeeId、name、age、effectiveDate、expirationDate
Excel 示例: |employeeId|姓名|年龄|有效日期|expiration_date|last_updated_ts|last_updated_by| |-- | -- |-- | -- | -- | -- | -- | |1 |约翰 |25 |2019-05-30| null |2019-05-20 |系统 | |2 |爱丽丝|28 |2017-08-15| 2021-02-15|2020-12-30 |人力资源 | |3 |鲍勃 |35 |2015-10-10| 2018-12-05|2018-11-20 |人力资源|
在这里,约翰从 2019 年 5 月 30 日开始活跃,没有到期日期。 Alice 目前处于活跃状态,但将于 2021 年 2 月 15 日到期。 Bob 已经过期,因为他过去有一个 expire_date。
要求:
输入将是上面的excel文件。我们将不得不进行下面提到的验证并将数据插入/更新到表中。
要求用户将使用 UI 上传此包含员工详细信息的 excel 文件,并应完成以下验证。
-
在excel中新增一列isDataValid。它将包含值“Y”或“N”。如果任何一行的验证失败,那么我们将其标记为“N”。否则,它是“Y”。
-
每一行都必须有员工 ID、姓名、年龄、有效日期。
-
expiration_date 是可选的。如果存在,expiration_date 必须 >= Effective_date
-
excel 的每一行都应该验证数据类型(例如:员工姓名应该只包含字符串,而不是数字等)。
-
excel每行5列,前4列是Employee表的复合主键列。 excel 中的每一行都必须与 Employee 表进行比较。
一个。如果该行已存在,但已过期:在 excel 中插入带有数据的新行(带有新的 Effective_date 和 expire_date)。 湾如果该行已存在,但未过期:不要插入带有数据的新行并将 isValid 更新为“N”。 C。如果该行不在表中,则插入数据并将 isValid 标记为“Y”。
输出:应通过 REST API 控制器将 excel 文件以及新创建的列“isValid”发送回用户,以便用户可以确定任何行中是否存在任何验证错误的excel。
流程:
- 从 REST API 获取 Excel 文件作为多部分文件输入。
- 使用 Apache POI 读取 excel 并获取工作簿和工作表。
- 迭代每一行,做上面的验证,检查Employee表是否存在记录,按照上面的验证规则在isValid列的excel行中相应地标记它们。
- 如果必须保存/更新该行,请将该行保留在 db 中。
- 在 excel 中的所有行都经过迭代、验证并标记为有效或无效后,将其从 REST API 发送回调用方。
问题:
- 对于大约有 150000 行的 excel 表,验证,我可以遵循什么方法?常规循环,对于 500-1000 条记录的小样本集(取决于数据),JPA saveAll 大约需要 1 分钟。
- 考虑使用批处理(Spring 批处理),但我如何使其足够快,以便用户能够在最多几分钟内下载 excel。
- 我找不到足够独特的重复问题。请在评论中提供链接。
请建议我一些设计选项,以根据我的要求完成操作。提前致谢。
代码:
我们使用 Apache POI 进行 excel 操作
控制器类
@PostMapping(path = "/employee/validation")
public ResponseEntity<InputStreamResource> validateEmployeeAndUpload(@RequestParam multipartfile excelFile) {
sxssfWorkbook workbook = new sxssfWorkbook();
HttpHeaders header = new HttpHeaders();
try{
//All validations handled here
workbook = validateAndGetWorkbook(excelFile);
ByteArrayOutputstream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toArray());
headers.add("Content-disposition","attachment; filename=Employee.xlsx");
return ResponseEntity.ok().headers(header).body(new InputStreamResource(inputStream));
}catch(Exception e){
....return bad request
}
}
员工实体
@PostMapping(path = "/employee/validation")
public ResponseEntity<InputStreamResource> validateEmployeeAndUpload(@RequestParam multipartfile excelFile) {
sxssfWorkbook workbook = new sxssfWorkbook();
HttpHeaders header = new HttpHeaders();
try{
//All validations handled here
workbook = validateAndGetWorkbook(excelFile);
ByteArrayOutputstream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toArray());
headers.add("Content-disposition","attachment; filename=Employee.xlsx");
return ResponseEntity.ok().headers(header).body(new InputStreamResource(inputStream));
}catch(Exception e){
....return bad request
}
}
EmployeeId 嵌入式 ID 类
@Entity
@Table(name="employee)
class Employee implements Serializable{
@EmbeddedId
EmployeeId employeeId;
@Column("expiration_date)
Date expirationDate;
@Column("last_updated_ts)
Timestamp lastUpdatedTs;
@Column("last_updated_by)
String lastUpdatedBy;
}
存储库接口
@Entity
@Table(name="employee)
class Employee implements Serializable{
@EmbeddedId
EmployeeId employeeId;
@Column("expiration_date)
Date expirationDate;
@Column("last_updated_ts)
Timestamp lastUpdatedTs;
@Column("last_updated_by)
String lastUpdatedBy;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。