SpringBoot2.0 基础案例(12):基于转账案例,演示事务管理操作
本文源码:GitHub·点这里 || GitEE·点这里
一、事务管理简介
1、事务基本概念
一组业务操作ABCD,要么全部成功,要么全部不成功。
2、特性:ACID
原子性:整体
一致性:完成
隔离性:并发
持久性:结果
3、隔离问题
脏读:一个事务读到另一个事务没有提交的数据
不可重复读:一个事务读到另一个事务已提交的数据(update)
虚读(幻读):一个事务读到另一个事务已提交的数据(insert)
4、隔离级别
read uncommitted:读未提交。
read committed:读已提交。解决脏读。
repeatable read:可重复读。解决:脏读、不可重复读。
serializable :串行化。都解决,单事务。
二、Spring管理事务
1、顶级接口

1)PlatformTransactionManager
平台事务管理器,spring要管理事务,必须使用事务管理器进行事务配置时,必须配置事务管理器。
2)TransactionDefinition
事务详情(事务定义、事务属性),spring用于确定事务具体详情,
例如:隔离级别、是否只读、超时时间 等
进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。
3)TransactionStatus
事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
spring底层根据状态进行相应操作。
2、事务状态

3、事务定义

PROPAGATION_REQUIRED , required , 必须  【默认值】
	支持当前事务,A如果有事务,B将使用该事务。
	如果A没有事务,B将创建一个新的事务。
PROPAGATION_SUPPORTS ,supports ,支持
	支持当前事务,A如果有事务,B将使用该事务。
	如果A没有事务,B将以非事务执行。
PROPAGATION_MANDATORY,mandatory ,强制
	支持当前事务,A如果有事务,B将使用该事务。
	如果A没有事务,B将抛异常。
PROPAGATION_REQUIRES_NEW , requires_new ,必须新的
	如果A有事务,将A的事务挂起,B创建一个新的事务
	如果A没有事务,B创建一个新的事务
PROPAGATION_NOT_SUPPORTED ,not_supported ,不支持
	如果A有事务,将A的事务挂起,B将以非事务执行
	如果A没有事务,B将以非事务执行
PROPAGATION_NEVER ,never,从不
	如果A有事务,B将抛异常
	如果A没有事务,B将以非事务执行
PROPAGATION_NESTED ,nested ,嵌套
	A和B底层采用保存点机制,形成嵌套事务。
掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
三、SpringBoot2.0管理事务
基于转账的案例演示,基于druid连接池配置。druid连接池在文章。
SpringBoot2.0 基础案例(07):集成Druid连接池,配置监控界面
1、新建转账表
CREATE TABLE account(
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50),
  money INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO account(username,money) VALUES('jack','10000');
INSERT INTO account(username,money) VALUES('rose','10000');
SELECT * FROM account;
2、基于事务手动管理器
该配置用于测试事务的手动管理。
/**
 * 事物管理器
 */
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager (DruidDataSource dataSource){
    LOGGER.info("【transactionManager 初始化...】");
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);
    return transactionManager;
}
/**
 * 创建事物手动管理模板
 */
@Bean(name = "transactionTemplate")
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager)
    LOGGER.info("【transactionTemplate 初始化...】");
    TransactionTemplate transactionTemplate = new TransactionTemplate() ;
    transactionTemplate.setTransactionManager(transactionManager);
    return transactionTemplate;
}
3、封装转账接口
接口方法
public interface AccountService {
    /**
     * 汇款
     */
    void out (String outer , Integer money);
    /**
     * 收款
     */
    void in (String inner , Integer money);
}
接口实现
@Service
public class AccountServiceImpl implements AccountService {
    @Resource
    private JdbcTemplate jdbcTemplate ;
    public void out(String outer, Integer money) {
        String sql = "update account set money = money - ? where username = ?";
        jdbcTemplate.update(sql, money,outer);
    }
    public void in(String inner, Integer money) {
        String sql = "update account set money = money + ? where username = ?";
        jdbcTemplate.update(sql, money,inner);
    }
}
4、封装三个测试接口
测试接口
public interface TradeService {
    /**
     * 转账交易:没有事务管理
     */
    void trade1(String outer ,String inner ,Integer money);
    /**
     * 转账交易:手动管理事务
     */
    void trade2(String outer ,String inner ,Integer money);
    /**
     * 转账交易:注解管理事务
     */
    void trade3(String outer ,String inner ,Integer money);
}
接口实现
@Service
public class TradeServiceImpl implements TradeService {
    @Resource
    private AccountService accountService ;
    @Resource
    private TransactionTemplate transactionTemplate ;
    @Override
    public void trade1(String outer, String inner, Integer money) {
        accountService.out(outer, money);
        // 抛出异常
        int i = 1/0;
        accountService.in(inner, money);
    }
    @Override
    public void trade2(String outer, String inner, Integer money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            public void doInTransactionWithoutResult(TransactionStatus arg0) {
                accountService.out(outer, money);
                // 抛出异常
                int i = 1/0;
                accountService.in(inner, money);
            }
        });
    }
    @Transactional(value="transactionManager",propagation= Propagation.REQUIRED)
    @Override
    public void trade3(String outer, String inner, Integer money) {
        accountService.out(outer, money);
        // 抛出异常
        int i = 1/0;
        accountService.in(inner, money);
    }
}
5、编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TransactionApplication.class)
public class TradeTest {
    @Resource
    private TradeService tradeService ;
    /**
     * 没有事务管理
     * jack 减少了1000块钱,但是rose得到1000块钱
     * 1	jack	9000
     * 2	rose	10000
     */
    @Test
    public void testTrade1 (){
        tradeService.trade1("jack", "rose", 1000);
    }
    /**
     * 手动管理事务
     * 1	jack	10000
     * 2	rose	10000
     */
    @Test
    public void testTrade2 (){
        tradeService.trade2("jack", "rose", 1000);
    }
    /**
     * 注解管理事务
     * 1	jack	10000
     * 2	rose	10000
     */
    @Test
    public void testTrade3 (){
        tradeService.trade3("jack", "rose", 1000);
    }
}
四、源代码地址
GitHub·地址
https://github.com/cicadasmile/spring-boot-base
GitEE·地址
https://gitee.com/cicadasmile/spring-boot-base

SpringBoot2.0 基础案例(12):基于转账案例,演示事务管理操作的更多相关文章
- (六)SpringBoot2.0基础篇- Redis整合(JedisCluster集群连接)
		
一.环境 Redis:4.0.9 SpringBoot:2.0.1 Redis安装:Linux(Redhat)安装Redis 二.SpringBoot整合Redis 1.项目基本搭建: 我们基于(五) ...
 - 4-9 基于Spring JDBC的事务管理(续)
		
10. 基于Spring JDBC的事务管理(续) 当需要方法是事务性的,可以使用@Transactional注解,此注解可以添加在: 接口 会使得此接口的实现类的所有实现方法都是事务性的 接口中的抽 ...
 - 【Spring实战】—— 16 基于JDBC持久化的事务管理
		
前面讲解了基于JDBC驱动的Spring的持久化管理,本篇开始则着重介绍下与事务相关的操作. 通过本文你可以了解到: 1 Spring 事务管理的机制 2 基于JDBC持久化的事务管理 Spring的 ...
 - 谈谈分布式事务之二:基于DTC的分布式事务管理模型[下篇]
		
[续上篇] 当基于LTM或者KTM的事务提升到基于DTC的分布式事务后,DTC成为了本机所有事务型资源管理器的管理者:此外,当一个事务型操作超出了本机的范 围,出现了跨机器的调用后,本机的DTC需要于 ...
 - SpringBoot2.0 基础案例(14):基于Yml配置方式,实现文件上传逻辑
		
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.文件上传 文件上传是项目开发中一个很常用的功能,常见的如头像上 ...
 - SpringBoot2.0 基础案例(13):基于Cache注解模式,管理Redis缓存
		
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.Cache缓存简介 从Spring3开始定义Cache和Cac ...
 - SpringBoot2.0基础案例(01):环境搭建和RestFul风格接口
		
一.SpringBoot 框架的特点 1.SpringBoot2.0 特点 1)SpringBoot继承了Spring优秀的基因,上手难度小 2)简化配置,提供各种默认配置来简化项目配置 3)内嵌式容 ...
 - SpringBoot2.0 基础案例(15):配置MongoDB数据库,实现增删改查逻辑
		
本文源码:GitHub·点这里 || GitEE·点这里 一.NoSQL简介 1.NoSQL 概念 NoSQL( Not Only SQL ),意即"不仅仅是SQL".对不同于传统 ...
 - SpringBoot2.0 基础案例(10):整合Mybatis框架,集成分页助手插件
		
一.Mybatis框架 1.mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获 ...
 
随机推荐
- quick check
 - 《CSS权威指南(第三版)》---第六章 文本属性
			
本章主要的内容是: 1.文本缩进: text-indent.行内元素无法缩进,一般用左内边距或外边距来创造这种效果. 2.文本对齐:text-align .只应用于块状元素. 3.行高:一般line- ...
 - poj2965 The Pilots Brothers' refrigerator —— 技巧性
			
题目链接:http://poj.org/problem?id=2965 题解:自己想到的方法是枚举搜索,结果用bfs和dfs写都超时了.网上拿别人的代码试一下只是刚好不超时的,如果自己的代码在某些方面 ...
 - JS高级调试技巧:捕获和分析 JavaScript Error详解
			
前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...
 - 获取url的参数
			
function getPrams () { var url, urlPrams, urlPramsArr=[], item=[], prams={}; url = location.href; if ...
 - python学习笔记:第五天( 字典)
			
Python3 字典 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 ,格 ...
 - linux命令学习笔记(52):ifconfig命令
			
许多windows非常熟悉ipconfig命令行工具,它被用来获取网络接口配置信息并对此进行修改.Linux系统拥有 一个类似的工具,也就是ifconfig (interfaces config).通 ...
 - CodeForces - 1000D:Yet Another Problem On a Subsequence (DP+组合数)
			
The sequence of integers a1,a2,…,aka1,a2,…,ak is called a good array if a1=k−1a1=k−1 and a1>0a1&g ...
 - 华为USG6500系列
			
华为USG6500: ssh 登录配置 time-range 相关配置:<USG6000V1>system-view Enter system view, return user view ...
 - WCF的用户名+密码认证方式(转)
			
概述 今天在做Master Data Service(后面简称MDS)项目时需要通过WCF来使用MDS的API,从而对MDS的数据进行操作.在这个过程中,遇到了一个棘手的问题,就是在客户端调用Web ...