本文源码: GitHub. 点这里 https://github.com/cicadasmile/spring-mvc-parent || GitEE. 点这里 https://gitee.com/cicadasmile/spring-mvc-parent
一, Spring 事务管理
1, 基础描述
Spring 事务管理的本质就是封装了数据库对事务支持的操作, 使用 JDBC 的事务管理机制, 就是利用 java.sql.Connection 对象完成对事务的提交和回滚.
- Connection conn = DriverManager.getConnection();
- try {
- // 自动提交设置为 false
- conn.setAutoCommit(false);
- // 执行增删改查操作
- // 当操作成功后手动提交
- conn.commit();
- } catch (Exception e) {
- // 出现异常, 回滚所有操作
- conn.rollback();
- e.printStackTrace();
- } finally {
- conn.colse();
- }
2, 事务常见概念
事务
事务是指作为单个逻辑工作单元执行的一系列操作 (SQL 语句). 这些操作要么全部成功, 要么全部不成功.
特性: ACID
原子性 (Atomicity): 事务中的多个操作要么都成功要么都失败
一致性 (consistency): 事务的执行的前后数据的完整性保持一致
隔离性 (isolation): 事务执行的过程中, 不应该受到其他事务的干扰
持久性 (durability): 事务一旦结束, 数据就持久到数据库
隔离问题
脏读: 一个事务读到另一个事务没有提交的数据
不可重复读: 一个事务前后多次读取相同数据, 数据内容不一致, update 场景问题
虚读 (幻读): 一个事务前后多次读取, 数据总量不一致, insert 场景问题
隔离级别
read uncommitted:
事务可以读取另一个未提交事务的数据.
read committed:
事务要等另一个事务提交后才能读取数据, 解决脏读.
repeatable read:
在开始读取数据时, 事务开启, 不再允许修改操作, 解决: 脏读, 不可重复读.
serializable:
最高事务隔离级别, 事务串行化顺序执行, 解决脏读, 不可重复读, 幻读. 但是效率低下, 耗数据库性能.
3, 事务管理 API 描述
PlatformTransactionManager
平台事务管理器, Spring 管理事务, 必须使用事务管理器进行事务配置时, 核心方法: 获取事务, 提交事务, 回滚事务.
TransactionDefinition
该对象封装事务详情 (事务定义, 事务属性), 例如: 隔离级别, 是否只读, 超时时间 等.
TransactionStatus
用于记录当前事务运行状态. 例如: 是否有保存点, 事务是否完成. Spring 底层根据状态进行相应操作.
4, 事务案例 SQL 语句
- CREATE TABLE user_account(
- id INT PRIMARY KEY AUTO_INCREMENT,
- username VARCHAR(50),
- money INT
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;;
- INSERT INTO user_account(username,money) VALUES('jack','5000');
- INSERT INTO user_account(username,money) VALUES('tom','5000');
- SELECT * FROM user_account ;
二, 编程式事务管理
1, 核心配置文件
- <!-- 配置事物管理器 -->
- <bean id="txManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 创建事物模板 -->
- <bean id="transactionTemplate"
- class="org.springframework.transaction.support.TransactionTemplate">
- <property name="transactionManager" ref="txManager" />
- </bean>
- <!-- 配置转账接口 -->
- <bean id="userAccountService"
- class="com.spring.mvc.service.impl.UserAccountServiceImpl">
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- <property name="transactionTemplate" ref="transactionTemplate" />
- </bean>
2, 演示案例
- @Service
- public class UserAccountServiceImpl extends JdbcDaoSupport implements UserAccountService {
- // 注入事物模板
- private TransactionTemplate transactionTemplate ;
- public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
- this.transactionTemplate = transactionTemplate;
- }
- @Override
- public void remittance(String remitTer, String receiver, int money) {
- transactionTemplate.execute(new TransactionCallbackWithoutResult() {
- public void doInTransactionWithoutResult(TransactionStatus arg0) {
- outMoney(remitTer,money);
- // System.out.println(1/0);
- innerMoney(receiver,money);
- }
- });
- }
- private void outMoney (String remitTer, int money){
- String outSql = "update user_account set money = money - ? where username = ?";
- this.getJdbcTemplate().update(outSql, money ,remitTer);
- }
- private void innerMoney (String receiver, int money){
- String inSql = "update user_account set money = money + ? where username = ?";
- this.getJdbcTemplate().update(inSql, money,receiver);
- }
- }
三, 事务代理工厂
1, 核心配置
- <!-- 配置转账接口 -->
- <bean id="userAccountService01"
- class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- <!-- 配置事务代理工厂 -->
- <bean id="proxyAccountService"
- class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <property name="proxyInterfaces" value="com.spring.mvc.service.UserAccountService01" />
- <property name="target" ref="userAccountService01" />
- <property name="transactionManager" ref="txManager" />
- <property name="transactionAttributes">
- <props>
- <!-- 默认传播行为, 隔离级别 -->
- <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
- <!-- 异常仍然提交事务
- <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.Exception</prop>
- -->
- </props>
- </property>
- </bean>
配置说明:
proxyInterfaces 代理接口
target 代理目标类
transactionManager 事务管理器
transactionAttributes
事务属性 (事务详情)
prop.key 指定方法使用当前事务配置
事务行为:
PROPAGATION 传播行为
ISOLATION 隔离级别
readOnly 是否只读
-Exception 异常回滚
+Exception 异常提交
2, 演示案例
- @Service
- public class UserAccountServiceImpl01 extends JdbcDaoSupport implements UserAccountService01 {
- @Override
- public void remittance(String remitTer, String receiver, int money) {
- outMoney(remitTer,money);
- System.out.println(1/0);
- innerMoney(receiver,money);
- }
- private void outMoney (String remitTer, int money){
- String outSql = "update user_account set money = money - ? where username = ?";
- this.getJdbcTemplate().update(outSql, money ,remitTer);
- }
- private void innerMoney (String receiver, int money){
- String inSql = "update user_account set money = money + ? where username = ?";
- this.getJdbcTemplate().update(inSql, money,receiver);
- }
- }
3, 测试代码
- public class Tx_Test_02 {
- @Test
- public void test1 (){
- String xmlPath = "spring-jdbc-tx-02.xml";
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
- UserAccountService01 accountService = (UserAccountService01)
- context.getBean("proxyAccountService");
- accountService.remittance("jack","tom",1000);
- }
- }
四, xml 配置事务
首先配置事务管理器, 然后配置事务属性, 最后基于 AOP 编程配置事务切入点.
1, 核心配置
- <!-- 配置事物管理器 -->
- <bean id="txManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 配置转账接口 -->
- <bean id="userAccountService01"
- class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- <!-- 配置事物详情 -->
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="remittance"
- propagation="REQUIRED"
- isolation="DEFAULT"/>
- </tx:attributes>
- </tx:advice>
- <!-- 事务切入点, 基于 AOP 编程 -->
- <aop:config>
- <aop:advisor
- advice-ref="txAdvice"
- pointcut="execution(* com.spring.mvc.service.UserAccountService01.*(..))"/>
- </aop:config>
五, 基于事务注解
配置事务管理器, 并启动事务注解的支持, 在目标类或目标方法添加 @Transactional 核心注解即可.
1, 核心配置
- <!-- 配置事物管理器 -->
- <bean id="txManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 支持事务注解 -->
- <tx:annotation-driven transaction-manager="txManager" />
2, 注解用法
注解写在接口方法上, 或者接口实现的方法上效果一样.
- public interface UserAccountService02 {
- @Transactional(rollbackFor = Exception.class)
- void remittance(String remitTer, String receiver, int money) ;
- }
六, 源代码地址
GitHub. 地址
https://github.com/cicadasmile/spring-mvc-parent
GitEE. 地址
https://gitee.com/cicadasmile/spring-mvc-parent
来源: https://www.cnblogs.com/cicada-smile/p/11985733.html