在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事务详解(二)实例的更多相关文章

  1. spring事务详解(二)简单样例

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  2. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  3. spring事务详解(一)初探事务

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...

  4. spring事务详解(五)总结提高

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.概念 ...

  5. spring事务详解(四)测试验证

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  6. Spring Aop 详解二

    这是Spring Aop的第二篇,案例代码很详解,可以查看https://gitee.com/haimama/java-study/tree/master/spring-aop-demo. 阅读前,建 ...

  7. spring事务详解(转载+高亮)

    spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...

  8. Spring、Spring事务详解;使用XML配置事务

    @Transactional可以设置以下参数: @Transactional(readOnly=false) // 指定事务是否只读的 true/false @Transactional(rollba ...

  9. JAVA框架之Spring【Spring事务详解】

    spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...

随机推荐

  1. Linux内核分析——第三周学习笔记20135308

    第三周 构造一个简单的Linux系统MenuOS 计算机三个法宝: 1.存储程序计算机 2.函数调用堆栈 3.中断 操作系统两把宝剑: 1.中断上下文的切换:保存现场和恢复现场 2.进程上下文的切换 ...

  2. opencv2 用imwrite 抽取并保存视频图像帧

    最近在写一个车辆检测程序,程序中需要获取图像帧,并保存为图片,且放到指定目录中去,我在网上查了很多发现都是opencv1的有关操作,没有opencv2的操作,我参考网上的例子,结合着用opencv2新 ...

  3. Jquery封装ajax

    Jquery封装ajax   Load方法     <!-- 将jquery.js导入进来 -->     <script type="text/javascript&qu ...

  4. DirectoryEntry_Properties属性的遍历(win2003)

    DirectoryEntry root = new DirectoryEntry(@"IIS://localhost/W3SVC"); string PInfo = "& ...

  5. 贝叶斯先验解释l1正则和l2正则区别

    这里讨论机器学习中L1正则和L2正则的区别. 在线性回归中我们最终的loss function如下: 那么如果我们为w增加一个高斯先验,假设这个先验分布是协方差为 的零均值高斯先验.我们在进行最大似然 ...

  6. dubbo的spi机制

    SPI SPI是一种扩展机制,在java中SPI机制被广泛应用,比如Spring中的SpringServletContainerInitializer 使得容器启动的时候SpringServletCo ...

  7. 【bzoj5004】开锁魔法II 组合数学+概率dp

    题目描述 有 $n$ 个箱子,每个箱子里有且仅有一把钥匙,每个箱子有且仅有一把钥匙可以将其打开.现在随机打开 $m$ 个箱子,求能够将所有箱子打开的概率. 题解 组合数学+概率dp 题目约定了每个点的 ...

  8. ubuntu 16.04 kdump 使用

    1.安装linux-crashdump及kdump sudo apt-get install linux-crashdump sudo apt-get install kexec-tool 2.重启电 ...

  9. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...

  10. 洛谷 P2862 [USACO06JAN]把牛Corral the Cows 解题报告

    P2862 [USACO06JAN]把牛Corral the Cows 题目描述 Farmer John wishes to build a corral for his cows. Being fi ...