Spring @Transaction配置演示样例及发生不回滚原因深度剖析
2016-04-13 09:26
411 查看
背景
近期在公司做的一个项目,用的是SpringMVC框架,数据库用的是MySql,刚開始并没有增加事务,后因业务须要必须事务处理。问题的产生和解决
使用事务,直接问百度,我选择的是注解的方式。在配置文件里配置事务管理器和驱动:
<tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean>
然后直接在service层加注解
package com.my.service.impl; import java.sql.SQLException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.my.constants.ServiceException; import com.my.dao.TestDao; import com.my.service.TestService; @Service public class TestServiceImpl implements TestService{ @Autowired private TestDao testDao; @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = { ServiceException.class }) public int insertUser(String userName) throws ServiceException { int id = 0; try { id = testDao.insertUser(userName); } catch (SQLException e) { throw new ServiceException(); } return id; } }
自然地,rollback的异常要和service抛出的异常一样才会回滚。
然后自觉得代码肯定没有问题。但是多次debug后到数据库取看都没有回滚,于是就直接在代码中增加错误代码int i = 5/0。并把exception的捕获改动一下
package com.my.service.impl; import java.sql.SQLException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.my.constants.ServiceException; import com.my.dao.TestDao; import com.my.service.TestService; @Service public class TestServiceImpl implements TestService{ @Autowired private TestDao testDao; @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = { ServiceException.class }) public int insertUser(String userName) throws ServiceException { int id = 0; try { id = testDao.insertUser(userName); int i = 5/0; } catch (Exception e) { throw new ServiceException(); } return id; } }
用上面的代码多次调试。始终没有回滚。
然后自然想到,可能Dao层有问题。然后去看Dao层代码,似乎真的有问题:
package com.my.dao.impl; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCreator; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import com.my.dao.TestDao; @Repository public class TestDaoImpl implements TestDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public int insertUser(final String userName) throws SQLException { final String sql = "INSERT INTO USER(NAME) VALUES(?);"; KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection con) throws SQLException { PreparedStatement ps = jdbcTem-plate.getDataSource().getConnection().prepareStatement(sql); ps.setString(1, userName); return ps; } }, keyHolder); return keyHolder.getKey().intValue(); } }
错误可能就在代码黄色块。
于是debug进去,看到Connectioncon中的autoCommit属性是false的,显然是被service层的事务管理到的,而jdbcTemplate.getDataSource().getConnection()是到链接池又一次获取的连接。这个连接显然没有被事务管理。它的autoCommit属性显然是true,所以这使得service层事务没有回滚。改起来非常easy,直接把代码中的黄色块改成PreparedStatement
ps = con.prepareStatement(sql);就能够了。
总结
遇到Springmvc事务不能回滚。解决的步骤:1. 检查配置文件中面有没有增加事务管理配置和驱动;
2. 检查数据库是否支持事务(比如MySql4.0 支持事务,Engine:InnoDB);
3. 检查代码块是否抛出异常,且事务的rollback的异常是抛出异常或者是抛出异常的父类。
4. 检查事务覆盖的代码块中的全部Connection是否都被这个事务覆盖(debug检查全部connection的autoCommit属性是不是被事务改成了false)。
相关文章推荐
- java 特种兵读后小记
- struts2的action总结
- Java实现Session模块来处理Token
- Java中 一个类实现了某接口 则必须实现该接口中的所有方法么?
- NullPointException-TabWidget.focusCurrentTab(TabWidget.java:401)
- 为什么学习Java三大框架SSH与MVC的设计模式
- JAVA代码读取配置文件信息 *.properties
- Struts2_模块包含 及Action总结
- 大数相乘问题--算法思想及Java实现解析(附详细注释)
- 【Spring】Spring集成Quartz
- JDK源码分析:java.lang.Boolean
- Java IO输入输出流 笔记
- Java基础-成员变量、局部变量和静态变量
- 《java第一季之入门篇》的想法
- 《java第一季之入门篇》的想法
- Java RMI 框架(远程方法调用)
- java里抽象类用法
- 集合(Java核心技术卷Ⅰ)
- java基于socket的组播协议实现代码(局域网聊天室)
- Java clone方法(下)