java - Spring MVC + Hibernate @Transactional 异常后不回滚

标签 java spring hibernate spring-mvc transactions

我正在尝试使用 Spring 创建一个 CMT,它会在每次出现异常时回滚事务。我的问题是,当我从一个注释为@Transactional 的方法对数据库进行多项更改时,即使我在某些操作后强制使用空指针,它也不会回滚操作。我将不胜感激。

遵循代码:

<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>

我的 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");
    }

我的服务:

@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);
        }
    }

我的 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);
        }
    }

}

最佳答案

您的事务没有回滚,因为没有抛出异常,换句话说 saveUpdateDeleteTest 正在捕获异常,这就是为什么 spring 事务代理无法检测到任何异常,因此没有回滚。移除 catch block ,您将看到事务将回滚。请注意 spring transaction回滚遵循 EJB 约定,即

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). 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.

因此,在您的情况下,如果您希望事务在出现任何异常时回滚,则需要进行自定义,如下所示:

@Transactional(rollbackFor = Exception.class)

关于java - Spring MVC + Hibernate @Transactional 异常后不回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27469104/

相关文章:

java - jar 中的名称 SNAPSHOT 是什么意思?/*snapshot*.jars 有什么问题?

spring - 如何从 spring boot 本身在嵌入式 tomcat 服务器上部署 spring boot web 应用程序

java - Spring AOP 与 Aspectj

java - 如何使用java + spring代码连接MFT服务器与其余暴露的执行上传,下载和列出文件等操作

java - @EnableTransactionManagement 和 @Transaction 不适用于 Hibernate

java - Eclipse 控制台中的 H2 数据库结果

mysql - 共享数据的一致性,使陈旧数据对象的写入无效

java - 匿名类Java中的匿名代码块

java - LWJGL 键盘输入不起作用

java - 如何在系统托盘中显示图标文件?