Java Spring@Transactional rollbackFor不适用于在代理对象外部调用的方法的已检查异常
我在结合Spring回滚Hibernate更新时遇到了一个问题 我有以下课程: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
@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”。希望任何人都能帮助我解决如何使其工作,我们将不胜感激
<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连接管理。如果所有查询都看到相同的连接,并且没有自动提交,那么实际上您有一个事务。我认为它需要调试。还有一件事可以帮助其他人