Spring mvc Spring JPA回滚不工作
我的web服务写入两个MySQL表(一个接一个;依赖于外键)。我已经让我的服务方法[upload(…])抛出一个强制异常,只是为了检查回滚功能。即使抛出异常,记录也会保存在文件存储表(第一个表)中。请帮我弄清楚出了什么问题。另外,如果任何上下文配置不正确,请告诉我。谢谢 文件:root-context.xmlSpring mvc Spring JPA回滚不工作,spring-mvc,spring-data-jpa,spring-transactions,transactional,Spring Mvc,Spring Data Jpa,Spring Transactions,Transactional,我的web服务写入两个MySQL表(一个接一个;依赖于外键)。我已经让我的服务方法[upload(…])抛出一个强制异常,只是为了检查回滚功能。即使抛出异常,记录也会保存在文件存储表(第一个表)中。请帮我弄清楚出了什么问题。另外,如果任何上下文配置不正确,请告诉我。谢谢 文件:root-context.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/s
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- Database -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/app?autoReconnect=true"/>
<property name="username" value="${datasource.username}"/>
<property name="password" value="${datasource.password}"/>
</bean>
<!-- JPA Vendor Adapter -->
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"></property>
</bean>
<!-- Entity Manager Factory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="packagesToScan" value="com.app.test.persistence" />
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Detect @Transactional -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- JPA Repositories -->
<jpa:repositories base-package="com.app.test.repository"/>
<!-- JASYPT Configuration -->
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="algorithm">
<value>PBEWithMD5AndDES</value>
</property>
<property name="password">
<value>com.app.test</value>
</property>
</bean>
<bean id="propertyConfigurer" class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>classpath:runtime.properties</value>
</list>
</property>
</bean>
<!-- Properties Util -->
<bean id="propertiesUtil" class="com.app.test.util.PropertiesUtil">
<property name="location" value="classpath:app.properties"></property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Detect @Controller -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/**" location="/WEB-INF/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.app.test" />
<beans:bean id="jsonMapper" class="com.fasterxml.jackson.databind.ObjectMapper"></beans:bean>
</beans:beans>
文件:FileStore.Java(Entity-2)
文件:filestoreserviceinpl.java
package com.app.test.service.impl;
@Service
@Transactional
public class FileStoreServiceImpl implements FileStoreService {
@Autowired
private FileStoreDAO fileStoreDAO;
@Autowired
private FileDAO fileDAO;
private static final Integer ID_LENGTH = 16;
@Override
@Transactional(rollbackFor={Exception.class, RuntimeException.class})
public String upload(UploadRequest jRequest, String uploadedFrom) throws Exception {
//String fileKey = null;
try {
//get the file content from packet
String fileContent = jRequest.getContent();
//compute checksum
String checksum = DigestUtils.sha1Hex(fileContent);
//check if similar file exists
if (!fileStoreDAO.checksumExists(checksum)) {
//create file store object
FileStore fStore = new FileStore();
fStore.setUniqueKey(RandomUtil.getRandomKey(checksum, ID_LENGTH));
fStore.setChecksum(checksum);
fStore.setUploadedOn(new Date());
fStore.setUploadedFrom(uploadedFrom);
fileStoreDAO.saveFileStore(fStore);
//create file object
File file = new File();
file.setFileStore(fStore);
file.setContent(fileContent.getBytes());
throw new Exception("Forced exception"); //Expecting Spring JPA to rollback the transaction; but not happenning :(
/*fileDAO.saveFile(file);
} else {
throw new Exception("Similar file already exists.");
}
} catch (Exception e) {
throw e;
}
//return fileKey;
}
}
文件:FileController.java
package com.app.test.controller;
@Controller
public class FileStoreController {
@Autowired
FileStoreService fileStoreService;
@Autowired
ObjectMapper jsonMapper;
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView processIndex(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView("index", null);
}
private String retrieveData(HttpServletRequest request) {
StringBuffer jBuffer = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jBuffer.append(line);
} catch (Exception e) {
return null;
}
return jBuffer.toString();
}
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String processUpload(HttpServletRequest request, HttpServletResponse response) {
UploadResponse jResponse = new UploadResponse();
try {
//retrieve request packet
String pData = retrieveData(request);
String fromAddress = request.getRemoteAddr();
if (null != pData && !("".equals(pData))) {
UploadRequest jRequest = jsonMapper.readValue(pData, UploadRequest.class);
String fileKey = fileStoreService.upload(jRequest, fromAddress);
UploadSuccess success = new UploadSuccess();
success.setFileId(fileKey);
success.setMessage("File uploaded successfully");
jResponse.setSuccess(success);
} else {
Error error = new Error();
error.setMessage("Packet is empty.");
jResponse.setError(error);
}
} catch (Exception e) {
Error error = new Error();
error.setMessage(e.getMessage());
jResponse.setError(error);
}
try {
return jsonMapper.writeValueAsString(jResponse);
} catch (Exception ex) {
return "Fatal exception occurred while processing upload request.";
}
}
}
您必须在根上下文文件上扫描服务,根上下文文件是您的应用程序上下文,但不在servlet上下文中,请参阅本文以了解有关 扫描
根上下文上的服务
:
<context:component-scan
base-package="com.app.test.service.impl"/>
默认情况下,spring transactionnal将回滚RuntimeException
,无需将它们添加到回滚类列表中:
@Transactional(rollbackFor=..)
编辑
Spring的事务管理仅针对未检查的异常回滚事务(RuntimeException)
谢谢你,影子。不幸的是,这些改变不起作用。服务仍在提交表中的数据。@madguy您能否从类级别删除
@Transactionnal
,并将其保留在方法上,然后重试againIt works。已从类级别删除“@Transactional”,并使该方法引发RuntimeException而不是Exception。交易正在回滚。
package com.app.test.service.impl;
@Service
@Transactional
public class FileStoreServiceImpl implements FileStoreService {
@Autowired
private FileStoreDAO fileStoreDAO;
@Autowired
private FileDAO fileDAO;
private static final Integer ID_LENGTH = 16;
@Override
@Transactional(rollbackFor={Exception.class, RuntimeException.class})
public String upload(UploadRequest jRequest, String uploadedFrom) throws Exception {
//String fileKey = null;
try {
//get the file content from packet
String fileContent = jRequest.getContent();
//compute checksum
String checksum = DigestUtils.sha1Hex(fileContent);
//check if similar file exists
if (!fileStoreDAO.checksumExists(checksum)) {
//create file store object
FileStore fStore = new FileStore();
fStore.setUniqueKey(RandomUtil.getRandomKey(checksum, ID_LENGTH));
fStore.setChecksum(checksum);
fStore.setUploadedOn(new Date());
fStore.setUploadedFrom(uploadedFrom);
fileStoreDAO.saveFileStore(fStore);
//create file object
File file = new File();
file.setFileStore(fStore);
file.setContent(fileContent.getBytes());
throw new Exception("Forced exception"); //Expecting Spring JPA to rollback the transaction; but not happenning :(
/*fileDAO.saveFile(file);
} else {
throw new Exception("Similar file already exists.");
}
} catch (Exception e) {
throw e;
}
//return fileKey;
}
}
package com.app.test.controller;
@Controller
public class FileStoreController {
@Autowired
FileStoreService fileStoreService;
@Autowired
ObjectMapper jsonMapper;
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView processIndex(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView("index", null);
}
private String retrieveData(HttpServletRequest request) {
StringBuffer jBuffer = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jBuffer.append(line);
} catch (Exception e) {
return null;
}
return jBuffer.toString();
}
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String processUpload(HttpServletRequest request, HttpServletResponse response) {
UploadResponse jResponse = new UploadResponse();
try {
//retrieve request packet
String pData = retrieveData(request);
String fromAddress = request.getRemoteAddr();
if (null != pData && !("".equals(pData))) {
UploadRequest jRequest = jsonMapper.readValue(pData, UploadRequest.class);
String fileKey = fileStoreService.upload(jRequest, fromAddress);
UploadSuccess success = new UploadSuccess();
success.setFileId(fileKey);
success.setMessage("File uploaded successfully");
jResponse.setSuccess(success);
} else {
Error error = new Error();
error.setMessage("Packet is empty.");
jResponse.setError(error);
}
} catch (Exception e) {
Error error = new Error();
error.setMessage(e.getMessage());
jResponse.setError(error);
}
try {
return jsonMapper.writeValueAsString(jResponse);
} catch (Exception ex) {
return "Fatal exception occurred while processing upload request.";
}
}
}
<context:component-scan
base-package="com.app.test.service.impl"/>
<context:component-scan
base-package="com.app.test.controller"/>
@Transactional(rollbackFor=..)
throw new RuntimeException("forced exception");