简体   繁体   English

Spring MVC + Hibernate @Transactional不是Rollinback异常之后

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM