当Spring将数据提交到数据库时为什么我的异常无法回滚事务

时间:2017-09-06 16:34:06

标签: java spring transactional

我使用Spring通过注释@Transactional来管理我的事务。但是,我发现它即使有RuntimeException也无法回滚。

首先,我解释一下我的应用结构。这是一个部署在Tomcat中的Web项目。我在DispatcherServlet中添加了web.xml。然后在servlet-context.xml中定义其配置。在servlet-context.xml中,我配置了事务。数据库是mysql-5.7.16-winx64

<tx:annotation-driven />

<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
</beans:bean>

<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <beans:property name="url" value="jdbc:mysql://localhost:3306/digitalmenu?useUnicode=true&amp;characterEncoding=UTF-8" />
  <beans:property name="username" value="root" />
  <beans:property name="password" value="root" />    
</beans:bean>

<beans:bean id="hibernate4AnnotatedSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"></beans:property>
<beans:property name="packagesToScan">
  <beans:list>
    <beans:value>com.shuishou.digitalmenu.account.models</beans:value>
  </beans:list>
</beans:property>
<beans:property name="hibernateProperties">
  <beans:props>
    <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</beans:prop>
    <beans:prop key="hibernate.show_sql">true</beans:prop>
    <beans:prop key="hibernate.format_sql">true</beans:prop>
    <beans:prop key="hibernate.use_sql_comments">true</beans:prop>
    <beans:prop key="hibernate.auto_close_session">true</beans:prop>
    <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>


    <!-- Enable the second-level cache  -->
    <beans:prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</beans:prop>
    <beans:prop key="hibernate.cache.use_second_level_cache">true</beans:prop>
    <beans:prop key="hibernate.cache.use_query_cache">true</beans:prop>
  </beans:props>
</beans:property>

例如,我有一个服务AccountService(已经由@Service注释)。这个类中有一个方法addAccount。我将@Transactional放在addAccount方法前面。

@org.springframework.transaction.annotation.Transactional(readOnly = false)
public Result addAccount(long userId, String username, String password) {
    UserData user = userDA.getUserByUsername(username);
    if (user != null)
        return new Result("account_existing");

    user = new UserData();
    user.setUsername(username);
    user.setPassword(password);
    userDA.saveUser(user);
}

这里,userDA是一个只调用hibernate会话来保存对象的存储库。

@Repository("userDA")
public class UserDataAccessor implements IUserDataAccessor {
    @Autowired
    protected SessionFactory sessionFactory;

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    @Override
    public Serializable saveUser(UserData user) {
        return sessionFactory.getCurrentSession().save(user);
    }
    ......
}

这是一种简单的方法。它不会抛出任何异常,所以一切都正常运行,但如果我改变一点让方法发生错误,我发现数据仍然存在于数据库中。在这里,我更改了addAccount方法,如下所示:

@Transactional(readOnly = false)
public Result addAccount(long userId, String username, String password) {
    UserData user = userDA.getUserByUsername(username);
    if (user != null)
        return new Result("account_existing");

    user = new UserData();
    user.setUsername(username);
    user.setPassword(password);
    userDA.saveUser(user);
    int i = 1/0; //-------------------here to create a RuntimeException
}

我在方法结束时制作了RuntimeException。但是,由于存在错误,因此不应将用户对象保留在数据库中。但数据仍然输入数据库。 我在userDA.saveUser(user);的行设置了一个断点我发现在java运行这行userDA.saveUser(user);之后,数据库被改变了,这与我想的不同。根据我的观点,数据库应该在函数运行完成后更改,没有任何异常。

因此,我有两个问题。

  1. 为什么在执行功能代码之前我的数据库发生了变化?
  2. 为什么在函数中出现错误/ RuntimeException后Spring不回滚?

0 个答案:

没有答案