Database 具有插入或更新机制的Spring批处理自定义itemWriter
我有一个带有基本块的Database 具有插入或更新机制的Spring批处理自定义itemWriter,database,spring,jpa,spring-batch,upsert,Database,Spring,Jpa,Spring Batch,Upsert,我有一个带有基本块的Spring批处理: 读取CSV文件 处理它(将一些编码值转换成另一个) 将结果写入数据库 问题 在某些情况下,我希望在我的自定义ItemWriter中插入或更新机制 示例:我可以在我的CSV C006;Test;OK;01/01/1970;1 C006;Test;OK;01/01/1970;5 您可以发现,除了最后一列之外,它们非常相似,策略如下: 如果我有一个“类似”实体,请检查数据库 如果为true,则使用您获得的最后一项更新该值(在本例中,第二行最后一列中的值为5)
Spring批处理:
读取CSV文件
处理它(将一些编码值转换成另一个)
将结果写入数据库
问题
在某些情况下,我希望在我的自定义ItemWriter
中插入或更新机制
示例:我可以在我的CSV
C006;Test;OK;01/01/1970;1
C006;Test;OK;01/01/1970;5
您可以发现,除了最后一列之外,它们非常相似,策略如下:
如果我有一个“类似”实体,请检查数据库
如果为true,则使用您获得的最后一项更新该值(在本例中,第二行最后一列中的值为5)
我已经做了什么?
@Embeddable
public class CarPK implements Serializable {
@Column
private String chassisSerialNumber;
@Column
private String engineSerialNumber;
public CarPK(){
// Your class must have a no-arq constructor
}
@Override
public boolean equals(Object obj) {
if(obj instanceof CarPK){
CarPK carPk = (CarPK) obj;
if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
return false;
}
if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
}
//setter and getter
}
在我的实体bean中,我添加了一个唯一的约束Anotion,如下所示:
@Table(name = "indicator",
uniqueConstraints = { @UniqueConstraint(columnNames =
{ "reference", "type", "status", "date" }) })
现在我可以肯定,我不能用同一列的数据持久化一个实体。然后,我创建了一个自定义的ItemWriter
,我试图捕获ConstraintViolationException,但它不起作用,我总是得到一个其他的exeption,即使我尝试了父exeption
那么你有什么想法或其他方法来做吗
我在考虑使用合并JPA功能?你觉得怎么样
我的自定义ItemWriter
@Component
public class ImportItemWriter implements ItemWriter<Indicator>{
@Autowired
protected IndicatorDao indicatorDao;
public void write(List<? extends Indicator> items) throws Exception {
for (Indicator item : items) {
Indicator indicator = new Indicator();
indicator.setReference(item.getReference());
indicator.setType(item.getType());
indicator.setStatus(item.getStatus());
indicator.setDueDate(item.getDueDate());
indicator.setValue(item.getValue());
try {
indicatorDao.persist(indicator);
} catch (ConstraintViolationException e) {
// TODO: handle exception
}
}
}
}
一个选项是使用分类复合编写器。分类器
将用于确定是执行插入还是更新。然后您需要配置两个委托,一个用于插入,一个用于更新。总结上述评论。
你想过直接使用吗。。该实现执行entityManger.merge(。。如果您的实体有一个复合pkey,您可以用这种方法求解
<job id="writeProductsJob" xmlns="http://www.springframework.org/schema/batch">
<step id="readWrite">
<tasklet>
<chunk reader="productItemReader" writer="productItemWriter" commit-interval="3" />
</tasklet>
</step>
</job>
<bean id="productItemWriter" class="org.springframework.batch.item.database.JpaItemWriter">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
复合主键
@Embeddable
public class CarPK implements Serializable {
@Column
private String chassisSerialNumber;
@Column
private String engineSerialNumber;
public CarPK(){
// Your class must have a no-arq constructor
}
@Override
public boolean equals(Object obj) {
if(obj instanceof CarPK){
CarPK carPk = (CarPK) obj;
if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
return false;
}
if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
}
//setter and getter
}
你想过直接使用吗。。该实现执行entityManger.merge(。。如果你的实体有一个复合pkey,你可以用这种方法来解决。是的,我以前使用过JpaItemWriter,但不起作用,我想合并只捕获主键,在我的情况下,我不关心它,我有一个特定的目的,同时检查4个属性你可以用4个属性创建一个复合主键:)。。但是如果你不能改变你的实体,那么你的“ImportItemWriter”也是一样的吗如果要创建复合主键,我将尝试一下。谢谢你解决了这个问题吗?如果是,您是如何解决的?这并没有解决捕获是否必须插入或更新的问题。此解决方案没有解决您需求的哪些部分?使用分类器的想法一点也不坏,但在我的情况下,我还有另一个问题。基本上,我希望找到一种机制,使我能够确定是否需要更新或插入项目。然后,插入或更新不是问题,但首先我需要了解情况。谢谢;)好主意,我以前不知道有类似复合Pkey的东西!但是在测试之前,从概念上讲,创建一个包含9个参数的复合pkey的实体是好的吗?如果每个字段的集合在数据库中必须是唯一的,我认为从概念上讲是正确的。是上帝的方式,也是因为它是由ORM处理的。无论是否为复合密钥,JPA都不会对性能产生显著影响。
@Embeddable
public class CarPK implements Serializable {
@Column
private String chassisSerialNumber;
@Column
private String engineSerialNumber;
public CarPK(){
// Your class must have a no-arq constructor
}
@Override
public boolean equals(Object obj) {
if(obj instanceof CarPK){
CarPK carPk = (CarPK) obj;
if(!carPk.getChassisSerialNumber().equals(chassisSerialNumber)){
return false;
}
if(!carPk.getEngineSerialNumber().equals(engineSerialNumber)){
return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
return chassisSerialNumber.hashCode() + engineSerialNumber.hashCode();
}
//setter and getter
}