我有Spring Batch
基本块:
问题
在某些情况下,我希望在我的自定义ItemWriter
中插入或更新机制。
例如:我可以在CSV
C006;Test;OK;01/01/1970;1
C006;Test;OK;01/01/1970;5
除了最后一栏,你可以发现它们非常相似,策略是:
我已经做了什么?
在我的实体bean中,我添加了一个 Unique Constraint anotation,如下所示:
@Table(name = "indicator",
uniqueConstraints = { @UniqueConstraint(columnNames =
{ "reference", "type", "status", "date" }) })
我现在肯定我不能坚持使用相同列数据的实体。然后,我创建了一个自定义ItemWriter
,我试图捕获 ConstraintViolationException ,但它不起作用,我总是得到另一个例外,即使我尝试了父版本。
那么你有什么想法或其他方法吗?
我考虑使用合并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
}
}
}
}
更新
解决了问题
使用Composite PKey
的想法很有意思,但我无法使用它,因为我必须使用9个密钥创建一个在性能方面不公平的复合。我决定将功能添加到我的DAO
(isDuplicated
),在我的自定义ItemWriter
中,我只是做了一个简单的测试:
if `isDuplicated()` then `updateEntity()` else `insertNew()`
答案 0 :(得分:6)
一种选择是使用ClassifierCompositeItemWriter
。 Classifier
将用于确定是执行插入还是更新。然后,您需要配置两个代理,一个用于插入,一个用于更新。
答案 1 :(得分:2)
总结以上评论。
您是否考虑过直接使用this? ..实现执行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>
通过@EmbeddedId,您可以构建复合主键以合并实体。见link
<强>实体强>
@Entity
@Table(name = "CAR")
public class Car {
@EmbeddedId
private CarPK carPK;
@Column
private String name;
}
复合主键
@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
}