一.myBatis单独使用时,使用SqlSession来处理事务
在前面的MyBatisStudy02工程中,新增MyBatisTxTest.java的测试类。
package com.bijian.study.test; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; public class MyBatisTxTest { private static final Logger log = LoggerFactory.getLogger(MyBatisTxTest.class); 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(1, "Test transaction"); user.setName("bijian2"); user.setAge(18); int affectedCount = mapper.updateUser(user); // 因后面的异常而未执行commit语句 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "Test transaction continuously"); user2.setName("bijian3"); user2.setAge(28); int affectedCount2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user2.getId()); int i = 2 / 0; // 触发运行时异常 session.commit(); // 提交会话,即事务提交 } finally { session.close(); // 关闭会话,释放资源 } } }
测试前数据库表user表的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
运行上面的单元测试,抛出java.lang.ArithmeticException:/ by zero异常。控制台输出如下内容:
21:29:59.797 [main] INFO com.bijian.study.test.MyBatisTxTest - 1 new record was inserted successfully whose id: 1 21:29:59.799 [main] INFO com.bijian.study.test.MyBatisTxTest - 1 new record was inserted successfully whose id: 1
此时我们再查看数据库表user表的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.01 sec)
二.和Spring集成后,使用Spring的事务管理
1.@Transactional方式
将工程MyBatisStudy03工程/WEB-INF/下的applicationContext.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.bijian.study.service.UserService" />
服务类:
package com.bijian.study.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import com.bijian.study.dao.IUserMapper; import com.bijian.study.model.User; @Service("userService") public class UserService { private static final Logger log = LoggerFactory.getLogger(UserService.class); @Autowired private IUserMapper mapper; public int batchUpdateUsersWhenException() { // 非事务性 User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 执行成功 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } @Transactional public int txUpdateUsersWhenException() { // 事务性 User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId()); User user2 = new User(1, "After exception"); int i = 1 / 0; // 抛出运行时异常,事务回滚 int affectedCount2 = mapper.updateUser(user2); // 未执行 log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId()); if (affectedCount == 1 && affectedCount2 == 1) { return 1; } return 0; } }
SpringIntegrateTxTest测试类如下:
package com.bijian.study.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bijian.study.service.UserService; public class SpringIntegrationTest { private static ApplicationContext ctx; static { ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); } @Test public void updateUsersExceptionTest() { UserService userService = (UserService) ctx.getBean("userService"); userService.batchUpdateUsersWhenException(); } @Test public void txUpdateUsersExceptionTest() { UserService userService = (UserService) ctx.getBean("userService"); userService.txUpdateUsersWhenException(); } }
运行单元测试updateUsersExceptionTest前数据库表user中的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
运行单元测试updateUsersExceptionTest后数据库表user中的数据如下:
mysql> select * from user; +----+------+------+------------------+ | id | name | age | address | +----+------+------+------------------+ | 1 | NULL | 0 | Before exception | +----+------+------+------------------+ 1 row in set (0.00 sec)
恢复数据库表user中的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
运行单元测试txUpdateUsersExceptionTest后数据库表user中的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
从上面的单元测试结果不难发现txUpdateUsersWhenException方法上面因注解了@Transactional事务生效了。
2.TransactionTemplate方式
在上面的application.xml中添加:
<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="txManager" /> </bean>
在UserService类加上如下内容:
@Autowired(required = false) private TransactionTemplate txTemplate; public int txUpdateUsersWhenExceptionViaTxTemplate() { int retVal = txTemplate.execute(new TransactionCallback<Integer>() { @Override public Integer doInTransaction(TransactionStatus status) { // 事务操作 User user = new User(1, "Before exception"); int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 User user2 = new User(1, "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 userService = (UserService) ctx.getBean("userService"); userService.txUpdateUsersWhenExceptionViaTxTemplate(); }
运行单元测试updateUsersWhenExceptionViaTxTemplateTest前数据库表user中的数据如下:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
运行单元测试updateUsersWhenExceptionViaTxTemplateTest后数据库表user中的数据如下,没有发生变化:
mysql> select * from user; +----+--------+------+-------------------+ | id | name | age | address | +----+--------+------+-------------------+ | 1 | bijian | 120 | hangzhou,westlake | +----+--------+------+-------------------+ 1 row in set (0.00 sec)
说明txUpdateUsersWhenExceptionViaTxTemplate方法因抛出运行时异常事务发生了回滚。
PS:
1.在有@Transactional注解的方法中,不可catch异常后不抛出
在有@Transactional注解的方法中,不可catch异常后不抛出,如不抛出,外围框架捕获不到异常,认为执行正确而提交。
@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; }
2.The prefix "tx" for element "tx:annotation-driven " is not bound
配置spring是碰到tx:annotation-driven is not bound 的问题,这个错误的原因很简单是在定义申明AOP的时候没有加载schema。修改applicationContext.xml配置文件头如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
3.运行时抛出java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor异常
原因是缺少包aopalliance-1.0.jar。
相关推荐
本篇文章将深入探讨MyBatis系列中的第五个主题——如何将MyBatis与Spring3进行集成,以实现更高效、更灵活的Java企业级应用开发。 MyBatis是一个轻量级的SQL映射框架,它允许开发者将SQL语句直接写在XML配置文件...
然后,配置MyBatis的核心文件`mybatis-config.xml`,定义数据源、事务管理器以及日志设置。例如: ```xml <property name="url" value="jdbc:mysql://localhost:3306/mydatabase?useSSL=false&...
在本篇中,我们将深入探讨"Mybatis系列一:开发环境搭建"的相关知识,这将包括如何设置一个基于Maven的Mybatis开发环境,以及如何理解并使用Mybatis的核心概念。首先,我们需要明白Mybatis是一个优秀的持久层框架,...
这个版本是MyBatis系列的一个稳定版本,包含了对先前版本的改进和新特性。 在MyBatis 3.4.5中,开发者可以期待以下关键特性: 1. **动态SQL**:MyBatis的强项之一是其强大的动态SQL支持。你可以直接在XML映射文件...
本资源是"Mybatis系列学习源码",适合初学者和有一定经验的开发者深入理解Mybatis的工作原理和实践应用。下面将详细探讨Mybatis的核心概念和关键功能。 1. **SqlSession与Executor** - **SqlSession**:它是...
【标题】:Mybatis系列教程Mybatis基本应用共9页.pdf 【描述】:这份教程是关于Mybatis基本应用的详细讲解,包含了9页丰富的内容,旨在帮助学习者深入理解和掌握Mybatis这一强大的持久层框架。 【标签】:Mybatis...
MyBatis需要配置数据源、事务管理器以及Mapper扫描器。Ext Js 3则需要配置Ajax proxy来与Spring MVC的RESTful API进行通信。 在角色管理模块的实现中,通常会包含以下功能: 1. 角色列表展示:使用GridPanel展示...
在本文中,我们将深入探讨如何将Spring MVC 3.1与MyBatis 3.1框架集成,并讨论其中涉及的关键技术,如事务管理、分页和JSON数据交换。此外,我们还将简要提及开发环境中使用的工具,如Eclipse 4.3、Maven 3.0.5和...
6. **插件与事务管理**:讨论插件如何与Mybatis的事务管理机制协同工作,确保数据的一致性。 7. **性能优化**:通过实例展示如何使用插件进行性能优化,比如减少不必要的数据库查询,提高SQL执行效率。 8. **最佳...
- 配置文件(mybatis-config.xml):这是MyBatis的核心配置,包含了数据源、事务管理器和Mappers的定义。 - 映射文件(UserMapper.xml):展示了如何定义SQL语句,如SELECT、INSERT、UPDATE和DELETE,并将它们映射...
- XML 配置文件:定义数据源、事务管理器、映射文件等,是 Mybatis 的全局配置。 - 映射文件(Mapper XML):包含 SQL 语句和结果映射,可以使用参数占位符和动态 SQL。 - 注解配置:在 Java 类上直接使用注解...
9. **事务管理**:Mybatis支持手动和自动事务管理,通过SqlSession的beginTransaction、commit和rollback方法控制。 10. **插件机制**:Mybatis允许自定义插件拦截Executor、StatementHandler、ParameterHandler和...
08`、`mybatis-02`、`mybatis-09`、`mybatis-01`、`mybatis-07`:这些文件可能代表了不同章节的源代码或者笔记,按照顺序可能是Mybatis的基础到进阶的各个主题,例如配置、SQL映射文件、动态SQL、事务管理等。...
MyBatis是一款优秀的ORM...本章主要内容:MyBatis与Spring如何集成,声明式事务管理,MapperScannerConfigurer本次课程,在YY上进行,YY频道:71042615课程回放:http://bbs.51cto.com/open/do/course/cid/65系列课程:...
5. **Spring与MyBatis整合**:解释如何将MyBatis集成到Spring项目中,利用Spring的事务管理。 最后,SpringMVC是Spring框架的Web模块,用于构建MVC架构的Web应用。SpringMVC面试专题可能包含: 1. **请求处理流程*...
【标题】"Mybatis系列教程Mybatis注解开发共9页.pdf" 提供的是一个关于Mybatis框架注解开发的教程,重点在于讲解如何在Mybatis中使用注解进行数据库操作。Mybatis是一个轻量级的Java持久层框架,它允许开发者通过...
6. **MyBatis与Spring整合**:在SSM架构中,MyBatis与Spring的整合可以实现事务管理、依赖注入等功能,简化项目开发。 7. **Mapper接口与XML映射文件**:Mapper接口定义业务方法,XML映射文件中定义SQL语句,通过...
【标题】:Mybatis系列教程Mybatis架构原理共4页.pdf 【描述】:这个压缩文件包含了一份关于Mybatis架构原理的系列教程,总计四页的内容。Mybatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。...