在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. 第一个spring,总结!

    陈志棚:界面跳转与框架 李天麟:游戏界面ui 徐侃:算法代码的设计 经过五天的时间,开会时候分配的任务,已经全部完成,在这期间中,我们遇到了一些问题.但是,经过android老师的指导后,app成功的 ...

  2. 3D开机动画

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  3. Windows 2012r2 以及以上版本远程提示错误的解决方法

    部分机器远程时会提示如图: 其实解决问题非常简单 .... 为了防止不会操作 完整的截图展示. 服务器下面进行处理 打开我的电脑 属性 打开远程设置 将框中的选项取消掉 然后就可以了.

  4. Triangle Counting UVA - 11401(递推)

    大白书讲的很好.. #include <iostream> #include <cstring> using namespace std; typedef long long ...

  5. 【BZOJ1201】[HNOI2005]数三角形(暴力)

    [BZOJ1201][HNOI2005]数三角形(暴力) 题面 BZOJ 洛谷 题解 预处理每个点向四个方向可以拓展的最大长度,然后钦定一个点作为三角形的某个顶点,暴力枚举三角形长度,检查这样一个三角 ...

  6. Python 通过gevent实现协程

    #coding:utf-8-*- '''协程(coroutine)又称微线程.纤程,是一种用户级的轻量级线程.协程有自己的寄存器上下文和栈.携程调度时,将寄存器上下文和栈 保存,在切换回来的时候恢复保 ...

  7. StratifiedKFold与GridSearchCV版本前后使用方法

    首先在sklearn官网上你可以看到: 所以,旧版本import时: from sklearn.cross_validation import GridSearchCV 新版本import时: fro ...

  8. Zabbix应用七:Zabbix发送短信报警

    Zabbix利用Python脚本调用短信API发送报警信息 一.先贴出python脚本: #!/usr/bin/python # _*_ coding:utf8 _*_ import sys impo ...

  9. CXF wsdl2java 生成java代码供客户端使用

    CXF wsdl2java 生成java代码供客户端使用 环境配置:1.下载apache-cxf-2.6.2在环境变量中配置CXF_HOME 值为E:\gavin\cxf\apache-cxf-3.0 ...

  10. nova-api源码分析(APP的创建)

    目录结构如下: 上面介绍了nova-api发布所用到的一些lib库,有了上面的基础知识,再来分析nova-api的发布流程,就比较轻松了.nova-api可以提供多种api服务:ec2, osapi_ ...