[英]Spring MVC + Hibernate @Transactional not Rollinback after exception
I'm trying to create a CMT with Spring that rollback the transactions each time an exception rises. 我正在尝试使用Spring创建一个CMT,每次异常上升时都会回滚事务。 My problem is that when I have multiple changes in the database from an method annotated as @Transactional, it's not rolling back the operations even when I force a null pointer after some operations.
我的问题是,当我从注释为@Transactional的方法对数据库进行多次更改时,即使我在某些操作后强制使用空指针,它也不会回滚操作。 I'll appreciate any help.
我会感激任何帮助。
Follow the code: 遵循以下代码:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="br.com.test" />
<mvc:annotation-driven/>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:property-placeholder location="classpath:config.properties"></context:property-placeholder>
<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource" p:basename="Messages">
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource"
p:driverClassName="${jdbc.driverClassName}"
p:password="${jdbc.password}"
p:url="${jdbc.url}"
p:username="${jdbc.username}">
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<bean class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
id="sessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
<property name="packagesToScan" value="br.com.test"></property>
</bean>
<mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />
</beans>
My Controller: 我的控制器:
@Controller
public class UserController {
@Resource(name="userService")
private UserService userService;
@RequestMapping(value="/user/create", method=RequestMethod.GET)
public ModelAndView createUser() throws GenericException {
this.userService.saveUpdateDeleteTest();
return new ModelAndView("createUser");
}
My Service: 我的服务:
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name="userDao")
private UserDao userDao;
@Override
@Transactional
public void saveUpdateDeleteTest() throws GenericException {
User user = new User();
user.setFirstName("Rogerio");
user.setLastName("R");
user.setEmail("r@gmail.com");
user.setPassword("123");
try {
this.userDao.save(user);
User u = this.userDao.findById(12l);
u.setFirstName("changed");
this.userDao.save(u);
User u2 = this.userDao.findById(11l);
this.userDao.delete(u2);
u2 = null;
u2.getCreated(); //Forcing a null pointer here
} catch (GenericException ge) {
throw ge;
} catch (Exception e) {
throw new ServiceException("Error at saving user. " + e.getMessage(), e);
}
}
My DAO: 我的DAO:
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
public void save(User user) throws DaoException {
try {
if (user.getId() == null) {
user.setCreated(new Date());
} else {
user.setLastUpdated(new Date());
}
this.sessionFactory.getCurrentSession().saveOrUpdate(user);
} catch (Exception e) {
throw new DaoException("Error at saving user.", e);
}
}
public void delete(User user) throws DaoException {
try {
this.sessionFactory.getCurrentSession().delete(user);
} catch (Exception e) {
throw new DaoException("Data access error. " + e.getMessage(), e);
}
}
public User findById(Long id) throws DaoException {
try {
Query query = this.sessionFactory.getCurrentSession().createQuery(
"from User u where u.id = :id");
query.setLong("id", id);
List<User> list = query.list();
User returnedObject = null;
if (list != null && list.size() > 0) {
returnedObject = list.iterator().next();
}
return returnedObject;
} catch (Exception e) {
throw new DaoException("Data access error. " + e.getMessage(), e);
}
}
}
Your transaction is not getting rollback because there is no exception thrown , in other words saveUpdateDeleteTest
is catching the exception, thats why spring transactional proxy cannot detect any exception and Hence no rollback. 您的事务没有得到回滚,因为没有抛出异常,换句话说
saveUpdateDeleteTest
正在捕获异常,这就是为什么spring transactional proxy无法检测到任何异常并且因此没有回滚。 Remove the catch block and you will see that transaction will rollback . 删除catch块,您将看到该事务将回滚。 PLease note that spring transaction rollback follows EJB Conventation ie
请注意, Spring事务回滚遵循EJB Conventation,即
While the EJB default behavior is for the EJB container to automatically roll back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException).
虽然EJB默认行为是EJB容器在系统异常(通常是运行时异常)上自动回滚事务,但EJB CMT不会在应用程序异常(即除java之外的已检查异常)上自动回滚事务.rmi.RemoteException)。 While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this.
虽然声明式事务管理的Spring默认行为遵循EJB约定(回滚仅在未经检查的异常时自动回放),但定制它通常很有用。
So in your case you need to customize if you want the transaction to be rolled back on any exception, like this: 因此,在您的情况下,您需要自定义是否要在任何异常上回滚事务,如下所示:
@Transactional(rollbackFor = Exception.class)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.