Java中使用Mysql数据库实现锁

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Java中使用Mysql数据库实现锁

文章目录

一、前言

上篇synchronized关键字与ReentrantLock实现扣减库存,单体应用中还可以使用mysql数据库来实现锁。先来简单实现下。

二、mysql数据库实现锁

数据库分为悲观锁和乐观锁

  • 悲观锁:读取数据时就锁住,这样其他线程或者操作必须要等到悲观锁释放后才获取锁进行操作。
  • 乐观锁: 读取数据时不进行数据锁,进行更新操作时检查数据是否被操作过,没有操作过才进行更新。

悲观锁

  1. select … lock in share mode 共享锁
  2. select … from for update 悲观锁
    共享锁容易造车死锁,这里只以for update为例进行讲解。

主要代码:

/**

    * 添加事务

    * @param productId

    * @return

    */

   @Transactional

   @Override

   public String deductStock(Integer productId) {

      Stock stock = stockMapper.selecStockForUpdate(productId);

      if(stock != null && stock.getStockNum() > 0 ){

          stock.setStockNum(stock.getStockNum() -1);

          int updateCount = stockMapper.updateById(stock);

          if (updateCount > 0 ){

              return "扣减库存成功";

          }else{

              return "扣减失败";

          }

      }

      return "库存库存失败:商品库存不存在或者库存为0";

   }

mapper:

  @Select("SELECT * FROM test.stock where product_id = #{productId} for update")

   Stock selecStockForUpdate(Integer productId);

乐观锁

实现方法:表加为数据库表增加一个数字类型的 “version” 字段来实现。

ALTER TABLE test.stock ADD version INT DEFAULT 0 NULL;

f2c66d93fead421c8518cdcd27f552f0.png

代码实现思路:当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录 的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新。

/**

    * 使用版本号实现扣减库存

    * @param productId

    * @return

    */

   @Override

   public String deductStockByVersion(Integer productId) {

       // 先查询库存是否充足

       Stock stock = stockMapper.selectById(productId);

       // 再减库存

       if (stock != null && stock.getStockNum() > 0) {

           // 获取版本号

           Integer version = stock.getVersion();

           stock.setStockNum(stock.getStockNum() - 1);

           // 每次更新 版本号 + 1

           stock.setVersion(stock.getVersion() + 1);

           // 更新之前先判断是否是之前查询的那个版本,如果不是重试

           if (this.stockMapper.update(stock, new UpdateWrapper<Stock>

                   ().eq("product_id", stock.getProductId()).eq("version", version)) == 0) {

               //库存失败再重试一次调用

               deductStockByVersion(productId);

           }

           return "扣减库存成功";

       }

       return "库存库存失败:商品库存不存在或者库存为0";

   }

执行的sql:

UPDATE `stock` SET product_id=?, stock_num=?, create_by=?, create_time=?, update_by=?, update_time=?, version=? WHERE (product_id = ? AND version = ?)

三、总结

本篇简单代码实现了单应用单数据库mysql数据库锁扣减库存,现在常用的都是使用版本号进行控制锁。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
12天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
30 2
|
1天前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
18 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
2天前
|
前端开发 Java 数据库
企业级JAVA、数据库等编程规范之命名风格 —— 超详细准确无误
文章详细阐述了企业级编程中Java和数据库等编程规范的命名风格,包括包名、类名、方法名、参数名、成员变量、局部变量、常量、抽象类、异常类、测试类、数据库及其字段和CSS等的命名规则。
6 0
企业级JAVA、数据库等编程规范之命名风格 —— 超详细准确无误
|
26天前
|
存储 关系型数据库 MySQL
【Java面试题汇总】MySQL数据库篇(2023版)
聚簇索引和非聚簇索引、索引的底层数据结构、B树和B+树、MySQL为什么不用红黑树而用B+树、数据库引擎有哪些、InnoDB的MVCC、乐观锁和悲观锁、ACID、事务隔离级别、MySQL主从同步、MySQL调优
【Java面试题汇总】MySQL数据库篇(2023版)
|
26天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
10天前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
42 5
|
14天前
|
算法 Java 关系型数据库
Java中到底有哪些锁
【9月更文挑战第24天】在Java中,锁主要分为乐观锁与悲观锁、自旋锁与自适应自旋锁、公平锁与非公平锁、可重入锁以及独享锁与共享锁。乐观锁适用于读多写少场景,通过版本号或CAS算法实现;悲观锁适用于写多读少场景,通过加锁保证数据一致性。自旋锁与自适应自旋锁通过循环等待减少线程挂起和恢复的开销,适用于锁持有时间短的场景。公平锁按请求顺序获取锁,适合等待敏感场景;非公平锁性能更高,适合频繁加解锁场景。可重入锁支持同一线程多次获取,避免死锁;独享锁与共享锁分别用于独占和并发读场景。
|
22天前
|
Java 数据库
JAVA并发编程-一文看懂全部锁机制
曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知! 今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。
|
22天前
|
安全 Java 开发者
Java并发编程中的锁机制解析
本文深入探讨了Java中用于管理多线程同步的关键工具——锁机制。通过分析synchronized关键字和ReentrantLock类等核心概念,揭示了它们在构建线程安全应用中的重要性。同时,文章还讨论了锁机制的高级特性,如公平性、类锁和对象锁的区别,以及锁的优化技术如锁粗化和锁消除。此外,指出了在高并发环境下锁竞争可能导致的问题,并提出了减少锁持有时间和使用无锁编程等策略来优化性能的建议。最后,强调了理解和正确使用Java锁机制对于开发高效、可靠并发应用程序的重要性。
20 3
|
1天前
|
存储 NoSQL Java
使用 Java 了解和学习 NoSQL 数据库:三个主要优势
使用 Java 了解和学习 NoSQL 数据库:三个主要优势
5 0