Spring批量自定义itemWriter,带有插入或更新机制

时间:2014-09-18 15:13:32

标签: database spring jpa spring-batch upsert

我有Spring Batch基本块:

  1. 阅读CSV文件。
  2. 处理它(将一些编码值转码为另一个编码值)。
  3. 将结果写入数据库。
  4. 问题

    在某些情况下,我希望在我的自定义ItemWriter中插入或更新机制。

    例如:我可以在CSV

    上获得这2行
    C006;Test;OK;01/01/1970;1
    C006;Test;OK;01/01/1970;5
    

    除了最后一栏,你可以发现它们非常相似,策略是:

    1. 检查数据库是否有“喜欢”实体
    2. 如果为true,请使用您获得的最后一项更新值(在我们的示例中,是最后一列中值为5的第二行)
    3. 我已经做了什么?

      在我的实体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个密钥创建一个在性能方面不公平的复合。我决定将功能添加到我的DAOisDuplicated),在我的自定义ItemWriter中,我只是做了一个简单的测试:

      if `isDuplicated()` then `updateEntity()` else `insertNew()`
      

2 个答案:

答案 0 :(得分:6)

一种选择是使用ClassifierCompositeItemWriterClassifier将用于确定是执行插入还是更新。然后,您需要配置两个代理,一个用于插入,一个用于更新。

答案 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
}