Spring @Transactional rollback不适用于已检查外部代理对象的方法的Exception

时间:2014-12-08 12:28:19

标签: java spring hibernate transactions annotations

我遇到了与Spring结合回滚Hibernate更新的问题。

我有以下课程:

@Service
@Transactional(readOnly = true)
public class DocumentServiceImpl extends AbstractGenericService<Document, IDocumentDao> implements DocumentService {

    @Override
    @Transactional(readOnly=false, rollbackFor = DocumentServiceException.class)
    public void saveDocument(final DocumentForm form, final BindingResult result, final CustomUserContext userContext) throws DocumentServiceException {
        Document document = locateDocument(form, userContext);
        if (!result.hasErrors()) {
            try {
                updateDocumentCategories(form, document);
                storeDocument(document, form.getDocumentId(), form.getFile());
                solrService.addDocument(document);
            } catch (IOException e) {
                result.reject("error.uploading.file");
                throw new DocumentServiceException("Error trying to copy the uploaded file to its final destination", e);
            } catch (SolrServerException e) {
                result.reject("error.uploading.file.solr");
                throw new DocumentServiceException("Solr had an error parsing your uploaded file", e);
            }
        }
    }

    @Override
    @Transactional(readOnly = false, rollbackFor = IOException.class)
    public void storeDocument(Document document, String documentId, CommonsMultipartFile uploadedFile) throws IOException {
        getDao().saveOrUpdate(document);
        if (StringUtils.isBlank(documentId)) {
            File newFile = documentLocator.createFile(document);
            uploadedFile.transferTo(newFile);
            // Todo: TEST FOR ROLLBACK ON FILE I/O EXCEPTION
            throw new IOException("this is a test");
        }
    }

接口未标记任何@Transactional注释。 saveDocument()方法是直接从我的Controller调用的,所以我希望使用该方法的@Transactional配置,特别是rollbackFor参数。但是,当抛出DocumentServiceException时,不会回滚任何内容(即getDao()。saveOrUpdate(document)被保留)。出于测试目的,我在storeDocument方法中添加了“throw new IOException”。希望任何人都可以帮助我如何使这项工作,非常感谢。

1 个答案:

答案 0 :(得分:0)

  1. 正确放置@Transactional注释。您不必在接口级别设置它,因为它不会自动继承(如果您的具体类实现了两个具有冲突事务设置的接口,那该怎么办)。

  2. 当你说方法被直接调用时,我假设你的接口是@Autowired,而不是具体的实现。

  3. 在服务方法中放置一个断点,并检查堆栈跟踪中是否有TransactionInterceptor条目。如果你没有它,那么你的事务管理配置是错误的,你根本就没有使用Spring事务管理。

  4. 丹尼斯的更新

    1. 还有一件事可以帮助其他人:

      我在applicationContext中使用了tx:annotation-driven。 applicationContext包含所有bean的组件扫描(无过滤器)。

      但是,dispatcherServlet上下文还包含所有bean的组件扫描(遗留代码,不要射击信使)。所以基本上我有我所有豆子的副本,因为他们在两种情况下都被扫描过。

      因为在dispatcherServlet上下文中创建的bean不包含tx:annotation-driven元素,所以dispatcherServlet上下文中的服务bean不是事务性的。

    2. 我不得不将dispatcherServlet上下文中的组件扫描更改为:

      <context:component-scan base-package="your/base/package" use-default-filters="false">    
          <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
      </context:component-scan> 
      

      因此,它只会实例化调度程序servlet上下文中的控制器(并且没有自动连接的依赖项,如其服务),以及applicationContext中的服务/ daos。

    3. 然后对applicationContext中的服务进行事务处理。