在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内核分析(第三周)

    构造一个简单的linux系统menuOS. 一.简介 1.两把宝剑:中断-上下文的切换(保存现场和恢复现场) 进程-上下文的切换 2.linux-3.18.6 arch/x86目录下的代码是我们重点关 ...

  2. Linux基础四(服务管理)

    目录 一.简介与分类 1.系统的默认运行级别 2.服务的分类 3.服务与端口 二.服务管理 1.RPM包服务管理 2.源码包服务管理 三.服务管理总结 一.简介与分类 1. 系统的运行级别 1.1 默 ...

  3. Beta 冲刺 五

    团队成员 051601135 岳冠宇 031602629 刘意晗 031602248 郑智文 031602330 苏芳锃 031602234 王淇 照片 项目进展 岳冠宇 昨天的困难 数据交换比较复杂 ...

  4. js css样式操作代码(批量操作)

    js css样式操作代码(批量操作) 作者: 字体:[增加 减小] 类型:转载 时间:2009-10-09   用js控制css样式,能让网页达到良好的的用户体验甚至是动画的效果.并且考虑到效率.   ...

  5. Linux命令(二) 复制文件 cp

    cp命令用来复制文件或目录,当复制多个文件时,目标文件参数必须为已经存在的目录,否则将出现错误. cp命令默认不能复制目录,复制目录必须使用 -R 选项.cp命令具备了 ln命令的功能. 命令格式: ...

  6. WM_CONCAT和LISTAGG 语法例子

    select to_char(replace(wm_concat(name), ',', '')) from codeitems where setid = 'A018' and ' like cod ...

  7. centos 6.9安装mysql

    1.确认mysql是否已安装,有下面的代码可知 [root@cdh1 zjl]# yum list installed mysql* Loaded plugins: fastestmirror, re ...

  8. MySQL查询where条件的顺序对查询效率的影响

    看到有资料说,where条件的顺序会影响查询的效率,根据的逻辑是: where条件的运行是从右到左的,将选择性强的条件放到最右边,可以先过滤掉大部分的数据(而选择性不强的条件过滤后的结果集仍然很大), ...

  9. Vue项目部署问题及解决方案

    Vue项目部署问题及解决方案 Vue-Router 有两种模式,默认是 hash 模式,另外一种是 history 模式. hash:也就是地址栏里的 # 符号.比如 http://www.examp ...

  10. java数组倒序查找值

    java语言里面没有arr[:-2]这种方式取值 只能通过  arr[arr.length-1-x]的方式取值倒数的 x(标示具体的某个值)