Spring transactional& JPA:保存多个实体时处理异常

时间:2016-10-20 13:28:35

标签: java spring hibernate spring-data-jpa transactional

文章是从网页上删除的,因此所有属性(如MediumSource等)最初的ID都为NULL,并且其字段中包含已删除的数据。在保存文章之前,* toEntities() - 方法确保重用DB中已存在的数据。如果数据是新的,则通过Article中的级联创建。<​​/ p>

可能会删除重复的文章,这会在保存时抛出“非唯一的异常”,这很好,但之后其他文章仍应保存。我想我正在努力正确处理这个异常。解决方法是检查实体是否存在,但这会导致95%的时间不必要的工作。

在代码中,您看到了我的最后一次尝试,我试图在自己的事务中保存每篇文章,但我得到以下例外:

  • [SqlExceptionHelper.java:129]密钥'UK_ftcejiicdrly4nl40b7lbvx6e'重复条目'5628BA1A0D4115E091B5EED94FEF5840'(副本由散列值确定)。
  • org.hibernate.AssertionFailure:null id in org.observer.media.model.Article条目(之后不要刷新会话 发生异常)

以下是ArticleService的代码。如果你发现这堂课的其他错误,我也很高兴听到它们。

@Service
public class ArticleService {

    @Autowired
    private ArticleRepository articleRepository;
    @Autowired
    private CategoryRepository categoryRepository;
    @Autowired
    private SourcesRepository sourcesRepository;
    @Autowired
    private MediumRepository mediumRepository;

    private final static Logger logger = LoggerFactory.getLogger("o.o.m.s.ArticleService");

    @Transactional
    public void save(Iterable<Article> articles) {
        for (Article article : articles) {
            save(article);
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(Article article) {
        dataToEntities(article);
        try {
            articleRepository.save(article);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional
    public void delete(Iterable<Article> articles) {
        if (articles == null) {
            return;
        }

        for (Article article : articles) {
            if (article.getId() != 0L) {
                delete(article);
            }
        }
    }

    @Transactional
    public void delete(Article article) {
        article.setMedium(null);
        article.setCategories(null);
        article.setSources(null);
        articleRepository.delete(article);
    }

    private void dataToEntities(Article article) {
        categoriesToEntities(article);
        sourcesToEntities(article);
        mediumToEntity(article);
    }

    private void mediumToEntity(Article article) {
        if (article.getMedium() == null) {
            return;
        }

        Medium medium = mediumRepository.findByName(article.getMedium().getName());
        if (medium != null) {
            article.setMedium(medium);
        }
    }

    private void sourcesToEntities(Article article) {
        Set<Source> sources = new HashSet<>();

        if (article.getSources() == null) {
            return;
        }

        for (Source source : article.getSources()) {
            Source entity = sourcesRepository.findByName(source.getName());
            if (entity != null) {
                sources.add(entity);
            } else {
                sources.add(source);
            }
        }

        article.setSources(sources);
    }

    private void categoriesToEntities(Article article) {
        Set<Category> categories = new HashSet<>();

        if (article.getCategories() == null) {
            return;
        }

        for (Category category : article.getCategories()) {
            category = categoryRepository.findByName(category.getName());
            categories.add(category);
        }

        article.setCategories(categories);
    }

}

编辑:

我跟进了可能的重复问题并尝试了

  1. NoRollBackFor-option,包含以下两种方法的所有可能异常:

    @Transactional(propagation = Propagation.REQUIRES_NEW,noRollbackFor = {ConstraintViolationException.class,MySQLIntegrityConstraintViolationException.class,DataIntegrityViolationException.class,AssertionFailure.class,RollbackException.class})

  2. 这导致“TransactionSystemException:无法提交JPA事务;嵌套异常是javax.persistence.RollbackException:事务标记为rollbackOnly”。

    1. 我放弃了StatelessSession方法,因为它偏离了JPA规范,并且因为级联根据文档不起作用。此外,它暴露了一个Session的变体,它更像是一个黑客,而不仅仅是暴露正常的休眠会话。

0 个答案:

没有答案