数据库面试必备之MySQL中的乐观锁与悲观锁

这篇文章主要介绍了数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数据一致性要求极高的场景,通过加锁确保数据一致,需要的朋友可以参考下

目录
  • 一、引言
  • 二、乐观锁
    • (一)原理
    • (二)应用场景
    • (三)示例代码
  • 三、悲观锁
    • (一)原理
    • (二)应用场景
    • (三)示例代码
  • 四、总结

    一、引言

    在多用户并发访问数据库的场景中,数据的一致性和完整性至关重要。为了避免并发操作导致的数据冲突问题,MySQL 提供了乐观锁和悲观锁两种并发控制机制。理解它们的工作原理、适用场景以及如何在实际代码中运用,对于开发高效且可靠的数据库应用程序具有关键意义。

    二、乐观锁

    (一)原理

    乐观锁基于一种乐观的假设,即认为在大多数情况下,并发事务之间不会发生冲突。它不会在事务开始时就对数据进行加锁,而是在提交数据更新之前,检查数据是否在事务执行期间被其他事务修改过。如果没有被修改,则允许提交更新;如果发现数据已经被修改,则根据具体的业务逻辑决定是重试更新操作还是抛出异常。

    (二)应用场景

    乐观锁适用于读多写少的场景,因为在这种情况下,并发冲突的概率相对较低。例如,在一个电商系统中,商品的浏览次数统计就是一个典型的读多写少的操作。多个用户可以同时查看商品详情页面,而对浏览次数的更新相对较少。

    (三)示例代码

    假设我们有一个 products 表,其中包含 id(主键)、namequantity 和 version 字段。version 字段将作为乐观锁的版本号。

    -- 创建 products 表
    CREATE TABLE products (
      id INT AUTO_INCREMENT PRIMARY KEY,
      name VARCHAR(50),
      quantity INT,
      version INT
    );
    

    以下是在 Java 代码中使用乐观锁更新商品数量的示例:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class OptimisticLockingExample {
        public static void main(String[] args) {
            // 数据库连接信息
            String url = "jdbc:mysql://localhost:3306/mydb";
            String username = "root";
            String password = "password";
    
            try (Connection connection = DriverManager.getConnection(url, username, password)) {
                // 开启事务
                connection.setAutoCommit(false);
    
                // 查询商品信息并获取当前版本号
                String selectSql = "SELECT quantity, version FROM products WHERE id =?";
                try (PreparedStatement selectStmt = connection.prepareStatement(selectSql)) {
                    selectStmt.setInt(1, 1); // 假设要更新 id 为 1 的商品
                    try (ResultSet resultSet = selectStmt.executeQuery()) {
                        if (resultSet.next()) {
                            int currentQuantity = resultSet.getInt("quantity");
                            int currentVersion = resultSet.getInt("version");
    
                            // 模拟业务逻辑,减少商品数量
                            int newQuantity = currentQuantity - 1;
    
                            // 更新商品数量和版本号,使用乐观锁机制
                            String updateSql = "UPDATE products SET quantity =?, version = version + 1 WHERE id =? AND version =?";
                            try (PreparedStatement updateStmt = connection.prepareStatement(updateSql)) {
                                updateStmt.setInt(1, newQuantity);
                                updateStmt.setInt(2, 1); // 商品 id
                                updateStmt.setInt(3, currentVersion);
                                int rowsUpdated = updateStmt.executeUpdate();
                                if (rowsUpdated == 0) {
                                    // 说明在更新之前数据被其他事务修改,乐观锁冲突
                                    System.out.println("乐观锁冲突,更新失败");
                                    connection.rollback();
                                } else {
                                    // 提交事务
                                    connection.commit();
                                    System.out.println("商品数量更新成功");
                                }
                            }
                        }
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    在上述代码中,首先查询商品的当前数量和版本号,然后根据业务需求计算新的数量。在更新时,通过 WHERE 子句中的版本号条件来检查数据是否被其他事务修改。如果更新的行数为 0,则表示发生了乐观锁冲突。

    三、悲观锁

    (一)原理

    与乐观锁相反,悲观锁持一种悲观的态度,认为在并发环境中,数据很可能会被其他事务修改。因此,在事务开始时,就对要操作的数据进行加锁,直到事务完成并提交或回滚后才释放锁。这样可以确保在事务执行期间,其他事务无法对锁定的数据进行修改操作。

    (二)应用场景

    悲观锁适用于写多读少且对数据一致性要求极高的场景。例如,在银行系统的转账操作中,涉及到对账户余额的修改,必须确保在整个转账事务过程中,账户余额数据不会被其他并发事务干扰,此时使用悲观锁可以有效避免数据不一致的问题。

    (三)示例代码

    同样以 products 表为例,在 MySQL 中可以使用 SELECT... FOR UPDATE 语句来实现悲观锁。

    -- 开启事务
    START TRANSACTION;
    
    -- 使用悲观锁查询商品信息并锁定行
    SELECT quantity FROM products WHERE id = 1 FOR UPDATE;
    
    -- 模拟业务逻辑,减少商品数量
    UPDATE products SET quantity = quantity - 1 WHERE id = 1;
    
    -- 提交事务
    COMMIT;
    

    在上述 SQL 代码中,SELECT quantity FROM products WHERE id = 1 FOR UPDATE 语句会对 id 为 1 的商品行进行锁定,直到事务提交或回滚。在锁定期间,其他事务如果尝试对该行数据进行修改操作,将会被阻塞,直到锁被释放。

    四、总结

    乐观锁和悲观锁是 MySQL 中两种重要的并发控制机制,它们各自适用于不同的应用场景。在实际开发中,需要根据业务需求、数据读写比例以及对数据一致性的要求等因素,合理选择使用乐观锁或悲观锁,以确保数据库系统在高并发环境下能够稳定、高效地运行,同时保证数据的完整性和一致性。

    到此这篇关于数据库面试必备之MySQL中的乐观锁与悲观锁的文章就介绍到这了,更多相关MySQL乐观锁与悲观锁内容请搜索骃骐网以前的文章或继续浏览下面的相关文章希望大家以后多多支持骃骐网!

    您可能感兴趣的文章:

    • 实例讲解MySQL中乐观锁和悲观锁
    • MySQL悲观锁与乐观锁的实现方案
    • Mysql悲观锁和乐观锁的使用示例
    • mysql 悲观锁与乐观锁的理解及应用分析
    • MySQL中的悲观锁与乐观锁
    • MYSQL悲观锁及乐观锁方式
    • mysql 乐观锁和悲观锁的具体使用
    • Mysql中悲观锁与乐观锁应用介绍
    • MySQL乐观锁和悲观锁具体实现

    相关推荐:

    年夜饭菜谱有哪些必备菜?

    年夜饭的必备菜没有绝对标准,但需兼顾“好意头”和“家乡味”。1. 年年有余:清蒸鱼可在鱼身下垫葱姜、蒸后淋热油和优质蒸鱼豉油增香;红烧鱼要先煎定型,加葱姜蒜爆香,调入料酒、生抽、老抽、糖慢炖,加一小块猪油更香浓;糖醋鱼按糖醋料酒生抽2:2:1:1调汁,炸鱼酥脆后快速烹入。2. 步步高升:炒年糕应选优质年糕,提前热水泡软,热锅冷油、油稍多,快速翻炒并可加少量水防干,搭配蔬菜肉丝更丰富。3. 金玉满堂...

    Python图像处理必备技巧分享

    本文系统梳理了Python图像处理的15项核心技能,涵盖图像读取、颜色转换、滤波、边缘检测、形态学操作、特征提取、分割、变换等关键技术,强调这些基础技能的组合应用可实现复杂图像处理任务,需要的朋友可以参考下 目录1. 图像读取与保存2. 图像颜色空间转换3. 图像裁剪与调整大小4. 图像滤波与平滑5. 边缘检测6. 阈值处理7. 形态学操作8. 直方图处理9. 特征检测与描述10. 图像配准与特征...

    三种简单生成SSH密钥的方法:Windows用户必备

    Windows系统重想要生成SSH密钥,我们今天提供三种方法,操作都很简单,详细请看下文介绍 在Windows 11上, 生成SSH密钥变得异常简便,用户可以根据个人喜好和习惯,通过多种不同的方式来完成这一操作。不仅仅是提高安全性并简化操作流程,SSH密钥还提供了诸多额外的优势,使其成为现代计算机用户的必备工具。以下是详细的指导方法。 使用命令提示符生成SSH密钥 利用Windows内置...

    Linux按功能分类的20种必备实用运维应用工具

    文章系统梳理了Linux运维领域20余款常用工具,涵盖系统管理、监控告警、容器编排、网络安全、备份恢复等方向,突出各工具在自动化、安全、高效等方面的优势,构建了完整的运维工具链以提升系统稳定性与运维效率 目录一、系统管理与配置1.1 Shell1.2 Ansible1.3 Puppet1.4 Chef二、监控与告警2.1 Prometheus2.2 Grafana2.3 Zabbix2.4 Nag...

    python爬虫需要学哪些东西 爬虫必备知识清单

    要成为python爬虫高手,你需要掌握以下关键技能和知识:1. python基础,包括基本语法、数据结构、文件操作;2. 网络知识,如http协议、html、css;3. 数据解析,使用beautifulsoup、lxml等库;4. 多线程和异步编程提升效率;5. 反爬虫策略,如user-agent伪装、ip轮换、请求频率控制;6. 数据存储和处理,使用sql、nosql数据库,并进行数据清洗和分...

    提升效率和装高手必备!100多条Windows运行命令大全

    很多 Windows 高手只需要输入一条命令,就能快速打开目标工具,我们整理了一份Windows运行命令大全,涵盖了 100+ 实用命令,帮你轻松提升效率 你是不是经常在 Windows 中为了打开某个「工具或功能」,翻遍了系统菜单,还要反复搜索才能找到?其实,很多 Windows 高手只需要输入一条命令,就能快速打开目标工具。 为了让更多人掌握这些高效技巧,我花时间整理了一份 Wind...

    学生党必备神器! vivo Pad SE 平板发布

    昨晚,vivo Pad SE正式发布,国补后的价格是849.15元起,作为一款入门级平板,vivo Pad SE专为学生党加入了专属学习中心,内置丰富的教育资源,涵盖学前教育与素质教育,名师讲堂精准教学 vivo Pad SE 平板昨晚正式发布,新机配备 12.3 英寸护眼柔光屏、搭载骁龙 4 Gen2 处理器、内置 8500mAh 电池,售价 999 元起。 标准版(蓝色 / 深灰色) 6GB+...

    VSCode 中 Vue.js 开发的必备插件

    在 vscode 中进行 vue.js 开发时,推荐使用以下插件:1. vetur,提供语法高亮和智能提示;2. vue vscode snippets,快速生成代码片段;3. eslint 和 prettier,确保代码质量和格式一致性。 引言 在现代前端开发中,Vue.js 已经成为了许多开发者的首选框架之一。它的灵活性和高效性使得开发者能够快速构建出用户友好的界面。然而,要充分发挥 Vue....

    Java并发编程必备之Synchronized关键字深入解析

    本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种使用方式:修饰代码块、修饰普通方法和修饰静态方法,感兴趣的朋友一起看看吧 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2. 可重入三、synchronized 的使用示例3.1 修饰代码块: 明确指定锁哪个对象3....

    键盘党必备福利! Windows 10 快捷键汇总

    在使用Windows 10操作系统时,掌握一些常用的快捷键可以大大提高工作效率,以下是一些Win10常用的组合快捷键,帮助你提升电脑操作技能 比较关注本博客的朋友都知道我会经常使用一些 Windows 快捷键,现在我将 Windows 10 快捷键汇总出来了,有兴趣的朋友可以收藏: Windows 10 基本快捷键 以下是建议每个 Windows 10 用户都须知道的基本键盘快捷键: 键盘快捷键动...