我遇到了与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”。希望任何人都可以帮助我如何使这项工作,非常感谢。
答案 0 :(得分:0)
正确放置@Transactional注释。您不必在接口级别设置它,因为它不会自动继承(如果您的具体类实现了两个具有冲突事务设置的接口,那该怎么办)。
当你说方法被直接调用时,我假设你的接口是@Autowired,而不是具体的实现。
在服务方法中放置一个断点,并检查堆栈跟踪中是否有TransactionInterceptor条目。如果你没有它,那么你的事务管理配置是错误的,你根本就没有使用Spring事务管理。
还有一件事可以帮助其他人:
我在applicationContext中使用了tx:annotation-driven。 applicationContext包含所有bean的组件扫描(无过滤器)。
但是,dispatcherServlet上下文还包含所有bean的组件扫描(遗留代码,不要射击信使)。所以基本上我有我所有豆子的副本,因为他们在两种情况下都被扫描过。
因为在dispatcherServlet上下文中创建的bean不包含tx:annotation-driven元素,所以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>
因此,它只会实例化调度程序servlet上下文中的控制器(并且没有自动连接的依赖项,如其服务),以及applicationContext中的服务/ daos。
然后对applicationContext中的服务进行事务处理。