Spring批处理无法跳过异常。任何人都可以建议我在这里错过了什么吗?
<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] WARN: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:键'promotion_id'的重复条目'1' 在org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
答案 0 :(得分:0)
如果您查看错误
javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException
您会注意到, PersistenceException 是引发的实际错误,而 ConstraintViolationException 是原因。这就是为什么向 skippable-exception-classes 中添加 ConstraintViolationException 无效的原因,但令我惊讶的是,甚至 PersistenceException 都不适合您。它对我有用(但是我顺便使用了Java配置)。此外,由于您还将 PersistenceException (这是 ConstraintViolationException 的超类)添加到 skippable-exception-classes ,因此添加了 ConstraintViolationException 似乎是多余的。
我假设您只希望跳过 ConstraintViolationException 。我尝试了两种解决方案(但使用Java配置):
实施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;
}
}
并将上面的船长设置为块中的 skip-policy ,并摆脱 skippable-exception-class 块。还要注意在此处设置 skip-limit 的方法:
<batch:chunk reader="transactionDataReader" writer="userPromotionWriter" commit-interval="100"
skip-policy="skipPolicy" />
<bean id="skipPolicy" class=pkg.ConstraintViolationExceptionSkipper">
<property name="skipLimit" value="100" />
</bean>
修改您的编写器以捕获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>