springboot事务的使用与简单的应用场景
使用介绍
下面的场景是基于springboot 自动配置的 DataSourceTransactionManager,我们仅在方法(或者类)加上 @Transactional 注解,就自动纳入 Spring 的事务管理了。下面回顾一些基础的熟悉介绍(根据个人情况选择性忽略)。
- 事务的传播行为:
行为 | 含义 |
---|---|
Propagation.REQUIRED(默认值) | 如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务 |
Propagation.SUPPORTS | 如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行 |
Propagation.MANDATORY | 如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常 |
Propagation.REQUIRES_NEW | 重新创建一个新的事务,如果当前存在事务,暂停当前的事务 |
Propagation.NOT_SUPPORTED | 以非事务的方式运行,如果当前存在事务,暂停当前的事务 |
Propagation.NEVER | 以非事务的方式运行,如果当前存在事务,则抛出异常 |
Propagation.NESTED | 和 Propagation.REQUIRED 效果一样 |
- 隔离级别属性:
事务的隔离级别,默认值为Isolation.DEFAULT
,可选有Isolation.READ_UNCOMMITTED
、Isolation.READ_COMMITTED
、Isolation.REPEATABLE_READ
、Isolation.SERIALIZABLE
。 - rollbackFor属性:指定能够触发事务回滚的异常类型,可以指定多个异常类型。
- noRollbackFor属性:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。
- readOnly属性:指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
- timeOut属性:事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
场景介绍
模拟场景为用户在拼夕夕买辣条,先扣款,扣款成功再减库存。这里使用buy、stockUpdate两个方法模拟业务。
- 数据库表
CREATE TABLE `a_account` (
`userid` int(11) NOT NULL COMMENT '账户ID',
`account` int(11) DEFAULT NULL COMMENT '账户余额',
PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='个人账户余额表';
CREATE TABLE `a_stocks` (
`goods` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品名称',
`stocks` int(11) DEFAULT NULL COMMENT '库存数量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='库存表';
初始余额10000元,辣条600包
- StocksMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ncs.rq.analysis.mapper.StocksMapper">
<update id="updateStock">
update a_stocks set stocks=stocks-1 WHERE goods = '辣条'
</update>
</mapper>
- AccountMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ncs.rq.analysis.mapper.AccountMapper">
<update id="updateAccount">
update a_account set account=account-100 where userid = 1762366
</update>
</mapper>
保证扣款成功且库存更新成功,失败一项则回滚
- 代码
AccountServiceImpl类