1. 概述

老话说的好:想要赚钱,就去看看有钱人有什么需求,因为有钱人钱多,所以赚的多。

言归正传,在Java项目的研发中,“锁”这个词并不陌生,最经典的使用场景是商品的超卖问题。

很多Java小白,通常会认为,给代码加上一把“锁”,就能解决多扣库存问题,却忽略了数据库事务的问题,今天我们就来做一个实验,分析一下商品超卖问题。

2. 场景介绍

有一款商品,库存只剩1件。

购买商品时,做三个动作,一是检查库存,二是扣库存,三是生成订单,三个动作在一个事务中执行。

模拟并发场景,使用10个线程同时执行用户购买商品的操作。

3. 代码实现

3.1 不加锁的代码实现

    @Transactional(rollbackFor = Exception.class)
public void buy() { // 查看是商品否有库存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("库存为 0");
} // 减库存
productRepository.reductCount(); // 生成订单
createOrder();
}

首先我们正常编写业务逻辑,用 @Transactional 注解控制事务。

经并发实验,产生了超卖的现象。

3.2 加锁的代码实现

    @Transactional(rollbackFor = Exception.class)
public synchronized void buy() { // 查看是商品否有库存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("库存为 0");
} // 减库存
productRepository.reductCount(); // 生成订单
createOrder();
}

这次我们使用 synchronized 关键字给方法加了把“锁”,理论上应该不会产生超卖现象了吧。

经实验,仍然产生了超卖现象。

因为虽然方法被锁住了,可是 @Transactional 注解 并没有及时的提交事务,导致库存没有及时扣减为0,因此还是超卖了。

3.3 正确使用事务的代码实现

    @Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition; // @Transactional(rollbackFor = Exception.class)
public synchronized void buy() { // 开启事务
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition); try {
// 查看是商品否有库存
Integer count = getProductCount();
if(count <= 0) {
throw new RuntimeException("库存为 0");
} // 减库存
productRepository.reductCount(); // 生成订单
createOrder(); // 事务提交
platformTransactionManager.commit(transactionStatus);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
// 事务回滚
platformTransactionManager.rollback(transactionStatus);
} }

这次我们不使用 @Transactional 注解管理事务了,改为手动管理事务。

经实验,解决了超卖现象。

4. 综述

今天聊了一下 Springboot在有锁的情况下如何正确使用事务,希望可以对大家的工作有所帮助。

欢迎帮忙点赞、评论、转发、加关注 :)

关注追风人聊Java,每天更新Java干货。

Springboot在有锁的情况下如何正确使用事务的更多相关文章

  1. 2020-03-27:分布式锁的问题,假如a线程在获得锁的情况下 网络波动 极端情况是断网了,这种情况是怎么处理的

    福哥答案2020-04-04:超时释放锁.

  2. laravel项目return back()->withErrors($validator)或return back()->with('errors','原密码错误!')在前台原密码错误的情况下不能正确显示错误信息,变成报错!

    被折磨的答案是 php artisan --version看一下版本,如果是5.2.26以上的,在路由处删除web中间件分组,还有问题再反馈

  3. Eureka在有虚拟网卡的情况下获取正确的IP

    发现问题 最近项目在Eureka注册时,发现一个问题:注册的IP地址不是 192.168.0.XXX 的网络IP,而是另外一个网段的地址,如图 通过 ipconfig 命令查看本机的IP地址发现,该I ...

  4. mysql什么情况下会触发表锁

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数 ...

  5. [数据库事务与锁]详解八:底理解数据库事务乐观锁的一种实现方式——CAS

    注明: 本文转载自http://www.hollischuang.com/archives/1537 在深入理解乐观锁与悲观锁一文中我们介绍过锁.本文在这篇文章的基础上,深入分析一下乐观锁的实现机制, ...

  6. [MySQL数据库之事务、读现象、数据库锁机制、多版本控制MVCC、事务隔离机制]

    [MySQL数据库之事务.读现象.数据库锁机制.多版本控制MVCC.事务隔离机制] 事务 1.什么是事务: 事务(Transaction),顾名思义就是要做的或所做的事情,数据库事务指的则是作为单个逻 ...

  7. mysql在生产环境下有大量锁表,又不允许重启的情况下的处理办法

    mysql在生产环境下有大量锁表,又不允许重启的情况下的处理办法 满头大汗的宅鸟该怎么办呢? mysql -u root -e "show processlist"|grep -i ...

  8. java 哪些情况下会使对象锁释放

    Java_多线程_锁释放 问:Java多线程运行环境中,在哪些情况下会使对象锁释放?答:由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的 ...

  9. Java高并发情况下的锁机制优化

    本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 1 public synchronized void syncMethod(){ 2 othercode ...

随机推荐

  1. Dynamics CRM实体系列之1:N、N:1以及N:N关系

    Dynamics CRM在实施过程中会遇到很多多个实体关联的问题,这样可以实现多个实体的记录通过关联的字段实现数据的综合展示,在Sql Server里面叫做外键,在Dynamics CRM叫做关系.D ...

  2. Vue.JS快速上手(指令和实例方法)

    1.声明式渲染 首先,我们要知道Vue是声明式渲染,那啥是声明式渲染,我们只需要告诉程序我们想要什么结果,其他的交给程序来做.与声明式渲染相对的是命令式渲染,即命令我们的程序去做什么,程序就会跟着你的 ...

  3. IMO 2021 第一题题解及相关拓展问题分析

    IMO 2021 第 1 题: 设整数 n ≥ 100.伊凡把 n, n + 1, ..., 2n 的每个数写在不同的卡片上.然后他将这 n + 1 张卡片打乱顺序并分成两堆.证明:至少有一堆中包含两 ...

  4. FPGA nios通过驱动LCD12864实现菜单界面和uart串口通信

    因为csdn无法插入视频,无法展示我这个实现的效果,这里我截了一些图,应该基本上也能明白了: 基本功能就是如图片所示,里面采用了菜单结构(这里编程需要一定得c语言编程技巧与数据结构知识),gpa是什么 ...

  5. CentOS管理firewalld防火墙

    1.查看防火墙某个端口是否开放 firewall-cmd --query-port=80/tcp 2.开放防火墙端口80 firewall-cmd --zone=public --add-port=8 ...

  6. 并发容器之ConcurrentMap

    一.concurentMap 1.数据结构,分段数组segment不扩容,里面的table扩容,每次翻倍,table中放的是entry链表的头地址: 2.初始化 segment和table的长度都是2 ...

  7. Java一般命名规范

    一.项目名称 最好用英文,所有单词全部用小写,如testjavaproject.studentmanagement等,当然也也可以用中文,如"学生管理系统"等. 二.Java pr ...

  8. 深度探索-Redis复制

    1.前言 本文介绍了Redis复制的主要流程和设计思想.通过本文的阅读,您大致能理解复制在软件架构方面的通用思想.在阅读本文之前,希望读者首先对Redis有一定的认识,对Redis的事件类型.和事件处 ...

  9. CVPR顶会论文爬取存入MySQL数据库(标题、摘要、作者、PDF链接和原地址)

    main.py import pymysql import re import requests # 连接数据库函数 from bs4 import BeautifulSoup def insertC ...

  10. VB自制计算器

    使用visual basic编写. 绘制如下的按钮界面: 然后代码如下: Dim a, temp, ans As Integer Dim op As String Sub showans() Text ...