spring事务详解(二)实例
在Spring中,事务有两种实现方式:
编程式事务管理: 编程式事务管理使用底层源码可实现更细粒度的事务控制。spring推荐使用TransactionTemplate,典型的模板模式。
申明式事务管理: 添加@Transactional注解,并定义传播机制+回滚策略。基于Spring AOP实现,本质是对方法前后进行拦截,
方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
关于spring事务实现方式:
引用博文:https://www.cnblogs.com/dennyzhangdd/p/9708499.html
关于分布式锁的实现方式:
引用博文:https://www.cnblogs.com/dennyzhangdd/p/7133653.html
提供一个具体实例来说明如何使用spring事务
基于数据库锁实现
1.悲观锁:select for update(一致性锁定读)

查询官方文档如上图,事务内起作用的行锁。能够保证当前session事务所锁定的行不会被其他session所修改(这里的修改指更新或者删除)。
对读取的记录加X锁,即排它锁,其他事不能对上锁的行加任何锁。 BEGIN;(确保以下2步骤在一个事务中:)
SELECT * FROM tb_product_stock WHERE product_id=1 FOR UPDATE--->product_id有索引,锁行.加锁
(注:条件字段必须有索引才能锁行,否则锁表,且最好用explain查看一下是否使用了索引,因为有一些会被优化掉最终没有使用索引)
UPDATE tb_product_stock SET number=number-1 WHERE product_id=1--->更新库存-1.解锁
COMMIT;
2.乐观锁:版本控制
选一个字段作为版本控制字段,更新前查询一次,更新时该字段作为更新条件。
不同业务场景,版本控制字段,可以0 1控制,也可以+1控制,也可以-1控制,这个随意。
BEGIN;(确保以下2步骤在一个事务中:)
SELECT number FROM tb_product_stock WHERE product_id=1--》查询库存总数,不加锁
UPDATE tb_product_stock SET number=number-1 WHERE product_id=1 AND number=第一步查询到的库存数--》number字段作为版本控制字段
COMMIT;
场景举例:
卖商品,先查询库存>0,更新库存-1。
例如:一种商品,有两件库存,多人来下单买,一个人一次只能买一件商品
创建表biz_shoe
CREATE TABLE `biz_shoe` (
`shoe_uuid` char(32) NOT NULL,
`inventory_number` int(11) DEFAULT NULL COMMENT '库存数量',
`is_putaway` int(1) DEFAULT NULL COMMENT '是否上架',
PRIMARY KEY (`shoe_uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
给库存赋值,如图

3.基于悲观锁实现
/**
* 悲观锁
* @param shoe
* @return
*/
@Transactional(添加spring事务注解)
@Override
public Integer vieShoe(BizShoe shoe) {
//抢单商品加悲观锁
BizShoe modleShoe = shoeMapper.lockForUpdate(shoe.getShoeUuid());
//商品库存
Integer number = modleShoe.getInventoryNumber();
System.out.println("库存:" + number);
System.out.println("线程名称:" + Thread.currentThread().getName());
if (number != 0) {
number = number - 1;
System.out.println("剩余库存:" + number);
modleShoe.setInventoryNumber(number);
shoeMapper.updateByPrimaryKeySelective(modleShoe);
} else {
AssertUtil.isTrue(number == 0, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
}
return number;
}
在mapping中具体sql语句
<select id="lockForUpdate" parameterType="java.lang.String" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List" /> FROM `biz_shoe` WHERE shoe_uuid = #{shoeUuid,jdbcType=CHAR} FOR UPDATE;
</select>
4.基于乐观锁
/**
* 乐观锁
* @param shoe
* @return
*/
@Transactional
@Override
public Integer vieShoe(BizShoe shoe) { //抢单商品加乐观锁
BizShoe modleShoe = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
//商品库存
Integer number = modleShoe.getInventoryNumber();
System.out.println("库存:" + number);
System.out.println("线程名称:" + Thread.currentThread().getName());
if(number >0){
int susus = shoeMapper.updateByShoeUuidInventoryNumber(shoe.getShoeUuid(),number);
System.out.println("更新成功 "+susus);
if(susus==1){//更新成功才算抢单成功
//商品库存
BizShoe modleShoeNew = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
System.out.println("新库存:" + modleShoeNew.getInventoryNumber());
}else{
AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
}
}else {
AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
}
return number;
}
sql语句
<update id="updateByShoeUuidInventoryNumber" parameterType="com.zstax.springtest.bean.BizShoe">
UPDATE biz_shoe SET inventory_number=inventory_number-1 WHERE
shoe_uuid=#{shoeUuid,jdbcType=CHAR} and inventory_number=#{InventoryNumber,jdbcType=INTEGER}
</update>
spring事务详解(二)实例的更多相关文章
- spring事务详解(二)简单样例
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- spring事务详解(一)初探事务
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...
- spring事务详解(五)总结提高
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.概念 ...
- spring事务详解(四)测试验证
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- Spring Aop 详解二
这是Spring Aop的第二篇,案例代码很详解,可以查看https://gitee.com/haimama/java-study/tree/master/spring-aop-demo. 阅读前,建 ...
- spring事务详解(转载+高亮)
spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...
- Spring、Spring事务详解;使用XML配置事务
@Transactional可以设置以下参数: @Transactional(readOnly=false) // 指定事务是否只读的 true/false @Transactional(rollba ...
- JAVA框架之Spring【Spring事务详解】
spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...
随机推荐
- 关于cocos2dx 关键字的问题
今天码代码,在创建新场景的时候,.h文件里 class Game : public cocos2d::Layer没有问题,在Game类里面,声明了它的成员之后,开始在.cpp文件里面实现这个类,到重 ...
- Answer My Questions
回答自己的问题,真棒!断电让自己的工作重来.真棒! 阅读以前自己的博客,发现问题都已经有了答案. (1).想要成为一名专业的软件工程师,首先得是有相关的资格证书,这个可以通过软考获得.然后在职场中锻炼 ...
- 第一个spring,总结!
陈志棚:界面跳转与框架 李天麟:游戏界面ui 徐侃:算法代码的设计 经过五天的时间,开会时候分配的任务,已经全部完成,在这期间中,我们遇到了一些问题.但是,经过android老师的指导后,app成功的 ...
- 数据平面可编程与SDN关系理解,以及数据平面可编程的理解
数据平面可编程与SDN关系 狭义 广义 数据平面可编程的理解 狭义 广义
- JS基础(五)自定义函数
作用:是为了让重复使用的语句,方便进行调用. 定义格式: function 自定义函数名 (参数1, 参数2,...) { 执行的语句 } 函数的封装:把语句放到函数中去的过程. 参数:通过参数的改变 ...
- Activiti的ACT_GE_PROPERTY表初始化
create table ACT_GE_PROPERTY ( NAME_ ), VALUE_ ), REV_ integer, primary key (NAME_) ) ENGINE=InnoDB ...
- createobjbyreplace(str,arr) js替换方法保存
<script> function createobjbyreplace(str,arr){ var len = arr.length; for(var i=0; i<len; i+ ...
- C# Stopwatch获取循环中某操作的时间消耗
在C#中通常使用DateTime来表示当前时间,可以在一个操作的前后分别使用一个DateTime对象获取当前时间,再将两个DateTime对象相减获得时间差(TimeSpan对象),从而得到这个操作耗 ...
- day5——Java 实现导出excel表 POI(转)
1.首先下载poi-3.6-20091214.jar,下载地址如下: http://download.csdn.net/detail/evangel_z/3895051 2.Student.java ...
- phaser3 微信小游戏入门
phaser与eget, laya, pixi.js本质上没什么区别. 都是渲染引擎. 其它的都是配角. phaser的特点是.代码容易理解 功能比较全面. 个人比较喜欢phaser的地方 twe ...