Java Spring@Transactional rollbackFor不适用于在代理对象外部调用的方法的已检查异常

Java Spring@Transactional rollbackFor不适用于在代理对象外部调用的方法的已检查异常,java,spring,hibernate,transactions,annotations,Java,Spring,Hibernate,Transactions,Annotations,我在结合Spring回滚Hibernate更新时遇到了一个问题 我有以下课程: @Service @Transactional(readOnly = true) public class DocumentServiceImpl extends AbstractGenericService<Document, IDocumentDao> implements DocumentService { @Override @Transactional(readOnly=fal

我在结合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");
        }
    }
@服务
@事务(只读=真)
公共类DocumentServiceImpl扩展AbstractGenericService实现DocumentService{
@凌驾
@事务性(readOnly=false,rollboor=DocumentServiceException.class)
public void saveDocument(最终DocumentForm表单、最终BindingResult结果、最终CustomUserContext用户上下文)引发DocumentServiceException{
文档=位置文档(表单、用户上下文);
如果(!result.hasErrors()){
试一试{
更新的文档类别(表格、文档);
storeDocument(document,form.getDocumentId(),form.getFile());
solrService.addDocument(文件);
}捕获(IOE异常){
result.reject(“error.upload.file”);
抛出新的DocumentServiceException(“尝试将上传的文件复制到其最终目的地时出错”,e);
}捕获(SolrServer异常){
result.reject(“error.upload.file.solr”);
抛出新的DocumentServiceException(“Solr在解析您上传的文件时出错”,e);
}
}
}
@凌驾
@事务性(readOnly=false,rollboor=IOException.class)
public void storeDocument(文档文档、字符串documentId、CommonMultipartFile uploadedFile)引发IOException{
getDao().saveOrUpdate(文档);
if(StringUtils.isBlank(documentId)){
File newFile=documentLocator.createFile(文档);
uploadedFile.transferTo(新文件);
//Todo:对文件I/O异常进行回滚测试
抛出新IOException(“这是一个测试”);
}
}
接口没有使用任何@Transactional注释进行标记。saveDocument()方法直接从我的控制器调用,因此我希望使用该方法的@Transactional配置,特别是rollbackFor参数。但是,当抛出DocumentServiceException时,不会回滚任何内容(即getDao()).saveOrUpdate(文档)被持久化)。出于测试目的,我在storeDocument方法中添加了一个“抛出新IOException”。希望任何人都能帮助我解决如何使其工作,我们将不胜感激

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

  • 当您说直接调用方法时,我假设您的接口是@Autowired,而不是具体的实现

  • 在服务方法中放置断点,并检查堆栈跟踪中是否有TransactionInterceptor条目。如果没有,则说明事务管理配置错误,根本不使用Spring事务管理

  • 丹尼斯的最新消息
  • 也许还有一件事可以帮助其他人:

    我在applicationContext中驱动了tx:annotation。applicationContext包含对所有bean的组件扫描(没有过滤器)

    然而,dispatcherServlet上下文还包含对所有bean的组件扫描(遗留代码,不要向messenger开枪),因此基本上我有一份所有bean的副本,因为它们在两种上下文中都被扫描过

    由于在dispatcherServlet上下文中创建的bean不包含tx:annotation驱动元素,因此dispatcherServlet上下文中的服务bean不是事务性的

  • 我必须将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> 
    
    
    
    因此,它将只实例化DispatcherServlet上下文中的控制器(没有像其服务那样的自动连接依赖项),以及applicationContext中的服务/DAO


  • 然后,来自applicationContext的服务被事务化。

    storeDocument上的
    @Transactional
    注释是无用的,因为它是一个内部方法调用,只有对代理的调用才会应用AOP。如果没有回滚,我怀疑您的设置有问题,并且没有实际应用任何事务。另一件事是,imho,让您的
    BindingResult
    绑定到web上有点奇怪(您直接使用的是与web相关的
    CommonsMultipartFile
    )。基本上,您的服务层现在依赖于web…启用spring日志来验证事务是否已启动@“M.Deinum”..storeDocument方法也被其他控制器单独调用,因此我们需要@Transactional注释。我知道如果间接调用它是无用的。@Andy transactions work..我通过抛出RuntimeException(而不是IOException)做了另一个测试,在这种情况下,它会回滚saveOrUpdate commit.darn,您的第3点是对的..我没有看到TransactionInterceptor。我猜还有其他东西(容器?)检测到RuntimeException时是否回滚更改?如果没有TransactionInterceptor,您只是在使用自动提交,因此每个语句都在其自己的事务中。因此,如果您有5条语句和4条工作语句,而最后一条失败,您仍然会看到前4条语句保持不变,而它只是最后一条回滚的语句。Not sur关于这一点…如果我在使用Hibernate保存记录后抛出RuntimeException,记录将回滚..因此事务范围必须大于您建议的范围?这还取决于db连接管理。如果所有查询都看到相同的连接,并且没有自动提交,那么实际上您有一个事务。我认为它需要调试。还有一件事可以帮助其他人