1

Spring Batch 无法跳过以下异常。任何机构都可以建议我在这里错过了什么吗?

<batch:job id="runPromotion">   
        <batch:step id="readPromotionStep">
            <batch:tasklet ref="processPromotion"></batch:tasklet>
            <batch:next on="SUCCESS" to="getPromotionalPoints" />
            <batch:end on="FAILED"></batch:end> 
            <batch:listeners>
                <batch:listener ref="queryProvider"/>           
            </batch:listeners>          
        </batch:step>
        <batch:step id="getPromotionalPoints">      
            <batch:tasklet >            
                <batch:chunk reader="transactionDataReader" writer="userPromotionWriter" commit-interval="100" skip-limit="100">                
                <batch:skippable-exception-classes >
                    <batch:include class="org.hibernate.exception.ConstraintViolationException"/>
                    <batch:include class="javax.persistence.PersistenceException"/>
                </batch:skippable-exception-classes>
                </batch:chunk>
            </batch:tasklet>
            <batch:listeners>
                <batch:listener ref="queryProvider"/>           
            </batch:listeners>


        </batch:step>   

    </batch:job>

以下是运行批处理时的错误:

2013-08-24 14:43:16,451 - [main] 警告:org.hibernate.engine.jdbc.spi.SqlExceptionHelper:143 - SQL 错误:1062,SQLState:23000 2013-08-24 14:43:16,451 - [ main] 错误:org.hibernate.engine.jdbc.spi.SqlExceptionHelper:144 - 键“promotion_id”的重复条目“1”javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException:键“的重复条目“1” org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)的promotion_id'

4

1 回答 1

0

如果您查看错误

javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException

您会注意到PersistenceException是引发的实际错误,而ConstraintViolationException是原因。这就是为什么将ConstraintViolationException添加到skippable-exception-classes不起作用的原因,但令我惊讶的是,即使PersistenceException也不适合您。它对我有用(但我顺便使用了 Java 配置)。此外,由于您还将PersistenceException (它是ConstraintViolationException的超类)添加到skippable-exception-classes,因此添加ConstraintViolationException似乎是多余的。

我假设您只想跳过ConstraintViolationException。我尝试了两种解决方案(但使用 Java 配置):

  1. 实施 SkipPolicy 以创建自定义船长。注意我们如何检查抛出异常的原因是否是ConstraintViolationException

    package pkg;
    
    import javax.persistence.PersistenceException;
    import org.hibernate.exception.ConstraintViolationException;
    import org.springframework.batch.core.step.skip.SkipLimitExceededException;
    import org.springframework.batch.core.step.skip.SkipPolicy;
    import org.springframework.stereotype.Component;
    
    public class ConstraintViolationExceptionSkipper implements SkipPolicy {
    
        private int skipLimit;
    
        @Override
        public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
          if(t instanceof PersistenceException && 
              t.getCause() instanceof ConstraintViolationException) {
            return true;
          }
          return false;
        }
    
        public void setSkipLimit(int skipLimit) {
          this.skipLimit = skipLimit;
        }
    }
    

    并将上述skipper设置为块中的skip-policy并摆脱skipable-exception-classes块。另请注意此处如何设置跳过限制

    <batch:chunk reader="transactionDataReader" writer="userPromotionWriter" commit-interval="100" 
        skip-policy="skipPolicy" />
    
    <bean id="skipPolicy" class=pkg.ConstraintViolationExceptionSkipper">
      <property name="skipLimit" value="100" />
    </bean>
    
  2. 修改您的编写器以捕获 PersistenceException 并将其作为 ConstraintVioaltionException 重新抛出。我不确定您是如何实现userPromotionWriter的,但下面是一个示例实现。它使用 JPA 进行持久化,显式刷新 EntityManager 并捕获并抛出一个新异常,就像我刚才所说的:

    package pkg;
    
    import java.util.List;
    
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    import org.hibernate.exception.ConstraintViolationException;
    import org.springframework.batch.item.ItemWriter;
    import org.springframework.stereotype.Component;
    
    @Component("userPromotionWriter")
    public class UserPromotionWriter implements ItemWriter<User> {
    
      @PersistenceContext
      private EntityManager entityManger;
    
      @Override
      public void write(List<? extends User> users) throws Exception {
          for(User user : users) {
            entityManger.persist(user);
            try {
                entityManger.flush();
            } catch(Exception e) {
                if(e.getCause() instanceof ConstraintViolationException) {
                    throw new ConstraintViolationException("Tried to insert a User record with a non-unique user_id of " + user.getUserId(), null, null);
                }
                throw e;
            }
            finally {
              entityManger.clear();
            }
          }
       }
    }
    

    现在,由于抛出的异常是 ConstraintViolationException(而不是 PersistenceException),因此以下将正常工作:

    <batch:chunk reader="transactionDataReader" writer="userPromotionWriter" commit-interval="100" skip-limit="100"> <batch:skippable-exception-classes > <batch:include class="org.hibernate.exception.ConstraintViolationException"/> </batch:skippable-exception-classes> </batch:chunk>

于 2019-06-07T20:58:04.547 回答