myBatis事务管理
1. myBatis单独使用时,使用SqlSession来处理事务:
- public class MyBatisTxTest {
- private static SqlSessionFactory sqlSessionFactory;
- private static Reader reader;
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- try {
- reader = Resources.getResourceAsReader("Configuration.xml");
- sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
- } finally {
- if (reader != null) {
- reader.close();
- }
- }
- }
- @Test
- public void updateUserTxTest() {
- SqlSession session = sqlSessionFactory.openSession(false); // 打开会话,事务开始
- try {
- IUserMapper mapper = session.getMapper(IUserMapper.class);
- User user = new User(9, "Test transaction");
- int affectedCount = mapper.updateUser(user); // 因后面的异常而未执行commit语句
- User user = new User(10, "Test transaction continuously");
- int affectedCount2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句
- int i = 2 / 0; // 触发运行时异常
- session.commit(); // 提交会话,即事务提交
- } finally {
- session.close(); // 关闭会话,释放资源
- }
- }
- }
2. 和Spring集成后,使用Spring的事务管理:
a. @Transactional方式:
在类路径下创建beans-da-tx.xml文件,在beans-da.xml(系列五)的基础上加入事务配置:
- <!-- 事务管理器 -->
- <bean id="txManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 -->
- <tx:annotation-driven transaction-manager="txManager" />
- <bean id="userService" class="com.john.hbatis.service.UserService" />
服务类:
- @Service("userService")
- public class UserService {
- @Autowired
- IUserMapper mapper;
- public int batchUpdateUsersWhenException() { // 非事务性
- User user = new User(9, "Before exception");
- int affectedCount = mapper.updateUser(user); // 执行成功
- User user2 = new User(10, "After exception");
- int i = 1 / 0; // 抛出运行时异常
- int affectedCount2 = mapper.updateUser(user2); // 未执行
- if (affectedCount == 1 && affectedCount2 == 1) {
- return 1;
- }
- return 0;
- }
- @Transactional
- public int txUpdateUsersWhenException() { // 事务性
- User user = new User(9, "Before exception");
- int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
- User user2 = new User(10, "After exception");
- int i = 1 / 0; // 抛出运行时异常,事务回滚
- int affectedCount2 = mapper.updateUser(user2); // 未执行
- if (affectedCount == 1 && affectedCount2 == 1) {
- return 1;
- }
- return 0;
- }
- }
在测试类中加入:
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = { "classpath:beans-da-tx.xml" })
- public class SpringIntegrateTxTest {
- @Resource
- UserService userService;
- @Test
- public void updateUsersExceptionTest() {
- userService.batchUpdateUsersWhenException();
- }
- @Test
- public void txUpdateUsersExceptionTest() {
- userService.txUpdateUsersWhenException();
- }
- }
b. TransactionTemplate方式
在beans-da-tx.xml中添加:
- <bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
- <constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="transactionManager" />
- </bean>
在UserService类加入:
- @Autowired(required = false)
- TransactionTemplate txTemplate;
- public int txUpdateUsersWhenExceptionViaTxTemplate() {
- int retVal = txTemplate.execute(new TransactionCallback<Integer>() {
- @Override
- public Integer doInTransaction(TransactionStatus status) { // 事务操作
- User user = new User(9, "Before exception");
- int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
- User user2 = new User(10, "After exception");
- int i = 1 / 0; // 抛出运行时异常并回滚
- int affectedCount2 = mapper.updateUser(user2); // 未执行
- if (affectedCount == 1 && affectedCount2 == 1) {
- return 1;
- }
- return 0;
- }
- });
- return retVal;
- }
在SpringIntegrateTxTest类中加入:
- @Test
- public void updateUsersWhenExceptionViaTxTemplateTest() {
- userService.txUpdateUsersWhenExceptionViaTxTemplate(); //
- }
注:不可catch Exception或RuntimeException而不抛出:
- @Transactional
- public int txUpdateUsersWhenExceptionAndCatch() { // 事务性操作,但是外围框架捕获不到异常,认为执行正确而提交。
- try {
- User user = new User(9, "Before exception");
- int affectedCount = mapper.updateUser(user); // 执行成功
- User user2 = new User(10, "After exception");
- int i = 1 / 0; // 抛出运行时异常
- int affectedCount2 = mapper.updateUser(user2); // 未执行
- if (affectedCount == 1 && affectedCount2 == 1) {
- return 1;
- }
- } catch (Exception e) { // 所有异常被捕获而未抛出
- e.printStackTrace();
- }
- return 0;
- }