数据库并发问题有那些以及解决办法

1. 数据库并发问题的具体表现

a. 脏读(Dirty Read)

定义:一个事务读取了另一个未提交事务所做的更改。

场景示例

  • 事务A:开始一个事务,更新账户余额为500元但未提交。
  • 事务B:在事务A未提交的情况下读取账户余额,得到500元。
  • 事务A:回滚其更改。
  • 结果:事务B读到了无效数据(脏读)。

影响:可能导致基于错误数据的后续操作或决策。

SQL示例

-- 事务A
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1; -- 更新但未提交

-- 事务B
SELECT * FROM accounts WHERE id = 1; -- 读取到事务A未提交的数据

b. 不可重复读(Non-repeatable Read)

定义:在一个事务中,同一个查询可能返回不同的结果,因为在此期间其他事务已经对数据进行了更新并提交。

场景示例

  • 事务A:开始一个事务,第一次查询账户余额为1000元。
  • 事务B:在事务A未完成时更新账户余额为900元并提交。
  • 事务A:再次查询账户余额,得到900元。
  • 结果:事务A在同一事务内两次查询的结果不一致。

影响:可能导致事务内部逻辑不一致。

SQL示例

-- 事务A
BEGIN;
SELECT * FROM accounts WHERE id = 1; -- 第一次查询,余额为1000

-- 事务B
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;

-- 事务A
SELECT * FROM accounts WHERE id = 1; -- 第二次查询,余额为900

c. 幻读(Phantom Read)

定义:当一个事务在两次相同的查询之间插入或删除了行,从而改变了结果集。

场景示例

  • 事务A:开始一个事务,查询所有账户余额大于1000元的记录,假设没有符合条件的记录。
  • 事务B:在事务A未完成时插入一条新记录,账户余额为1500元。
  • 事务A:再次执行相同查询,发现新记录。
  • 结果:事务A看到“幻影”数据。

影响:可能导致事务内部逻辑不一致。

SQL示例

-- 事务A
BEGIN;
SELECT * FROM accounts WHERE balance > 1000; -- 第一次查询,无记录

-- 事务B
INSERT INTO accounts (id, balance) VALUES (2, 1500);
COMMIT;

-- 事务A
SELECT * FROM accounts WHERE balance > 1000; -- 第二次查询,发现新记录

d. 丢失更新(Lost Update)

定义:两个事务同时读取同一数据项,并对其进行修改。其中一个事务的更新会覆盖另一个事务的更新,导致数据丢失。

场景示例

  • 事务A:读取账户余额为1000元。
  • 事务B:同时读取同一账户余额为1000元。
  • 事务B:将余额减少100元并提交,余额变为900元。
  • 事务A:将余额减少100元并提交,余额变为900元(但实际上应为800元)。
  • 结果:事务A的更新覆盖了事务B的更新,导致数据丢失。

影响:数据丢失或不一致。

SQL示例

-- 事务A
BEGIN;
SELECT * FROM accounts WHERE id = 1; -- 读取余额为1000

-- 事务B
BEGIN;
SELECT * FROM accounts WHERE id = 1; -- 读取余额为1000
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;

-- 事务A
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT; -- 最终余额为900,而非800

2. 解决并发问题的方法

a. 使用事务与隔离级别

详细步骤

  1. 选择合适的隔离级别:根据应用需求选择适当的隔离级别。

    • Read Uncommitted:允许脏读。
    • Read Committed:防止脏读,但允许不可重复读和幻读。
    • Repeatable Read:防止脏读和不可重复读,但允许幻读。
    • Serializable:防止所有并发问题,但性能较低。
  2. 使用SQL事务控制语句

    • BEGIN 或 START TRANSACTION:开始一个事务。
    • COMMIT:提交事务。
    • ROLLBACK:回滚事务。

实例

-- 设置为可序列化隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;

-- 锁定行以防止其他事务修改
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

-- 更新账户余额
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

COMMIT;

应用场景:适用于高一致性要求的应用场景,如金融交易系统。

b. 应用乐观锁

详细步骤

  1. 添加版本号或时间戳字段:在表中添加一个版本号或时间戳字段。
  2. 每次更新数据时检查版本号:确保版本号匹配后再进行更新。

表结构示例

CREATE TABLE accounts (
    id INT PRIMARY KEY,
    balance DECIMAL(10, 2),
    version INT DEFAULT 0
);

-- 插入初始数据
INSERT INTO accounts (id, balance) VALUES (1, 1000);

更新示例

-- 假设@expectedVersion是从上一次读取中获取的
UPDATE accounts 
SET balance = balance - 100, version = version + 1 
WHERE id = 1 AND version = @expectedVersion;

应用场景:适用于读多写少的场景,如博客系统中的文章更新。

c. 实施悲观锁

详细步骤

  1. 开始事务:使用BEGINSTART TRANSACTION开始一个事务。
  2. 锁定需要操作的数据:使用SELECT ... FOR UPDATE锁定需要操作的数据。
  3. 进行必要的更新操作:在锁定状态下进行更新操作。
  4. 提交事务:使用COMMIT提交事务。

实例

BEGIN;

-- 锁定行,阻止其他事务修改
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

-- 更新账户余额
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

COMMIT;

应用场景:适用于写操作频繁且冲突可能性大的场景,如银行转账系统。

d. 利用数据库连接池和资源管理

详细步骤

  1. 选择合适的数据库连接池实现:如HikariCP、C3P0等。
  2. 配置连接池参数
    • maximumPoolSize:最大连接数。
    • minimumIdle:最小空闲连接数。
    • idleTimeout:空闲连接超时时间。
    • maxLifetime:连接的最大生命周期。

Java代码示例

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

public class DatabaseConnectionPool {
    public static void main(String[] args) {
        HikariConfig config = new HikariConfig();
        
        // 设置数据库连接信息
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        config.setUsername("user");
        config.setPassword("password");

        // 设置连接池大小
        config.setMaximumPoolSize(10); // 最大连接数
        config.setMinimumIdle(5);      // 最小空闲连接数
        config.setIdleTimeout(30000);   // 空闲连接超时时间(毫秒)
        config.setMaxLifetime(1800000); // 连接的最大生命周期(毫秒)
        
        HikariDataSource dataSource = new HikariDataSource(config);
        
        // 使用dataSource获取连接并进行操作
        try (Connection connection = dataSource.getConnection()) {
            PreparedStatement stmt = connection.prepareStatement("SELECT * FROM accounts WHERE id = ?");
            stmt.setInt(1, 1);
            ResultSet rs = stmt.executeQuery();
            
            while (rs.next()) {
                System.out.println("Account ID: " + rs.getInt("id"));
                System.out.println("Balance: " + rs.getBigDecimal("balance"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

应用场景:适用于高并发场景下的数据库访问优化,如大型电商系统的订单处理模块。

3. 总结

针对多线程环境下的数据库并发问题,可以通过以下几种策略来解决:

  • 事务与隔离级别:根据应用需求选择合适的隔离级别,确保数据的一致性和完整性。例如,使用Serializable隔离级别可以防止所有并发问题,但会影响性能。
  • 乐观锁:适用于读多写少的场景,减少锁定带来的性能损耗。通过版本号或时间戳字段来检测冲突。
  • 悲观锁:适用于写操作频繁且冲突可能性大的场景,直接锁定数据防止其他事务修改。使用SELECT ... FOR UPDATE语句来锁定行。
  • 数据库连接池管理:优化连接池配置,提高系统的并发处理能力。确保连接池中的连接及时释放,避免连接耗尽。

每种方法都有其适用的场景,开发者需要根据具体业务需求和系统特点灵活选用。通过合理的并发控制策略,可以有效避免数据错乱问题,确保数据库的稳定运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/978239.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

模型和数据集的平台之在Hugging Face上进行模型下载、上传以及创建专属Space

模型下载 步骤: 注册Hugging Face平台 https://huggingface.co/ 新建一个hf_download_josn.py 文件 touch hf_download_josn.py 编写hf_download_josn.py文件 import os from huggingface_hub import hf_hub_download# 指定模型标识符 repo_id "inter…

脚本无法获取响应主体(原因:CORS Missing Allow Credentials)

背景: 前端的端口号8080,后端8000。需在前端向后端传一个参数,让后端访问数据库去检测此参数是否出现过。涉及跨域请求,一直有这个bug是404文件找不到。 在修改过程当中不小心删除了一段代码,出现了这个bug&#xff…

C#实现本地AI聊天功能(Deepseek R1及其他模型)。

前言 1、C#实现本地AI聊天功能 WPFOllamaSharpe实现本地聊天功能,可以选择使用Deepseek 及其他模型。 2、此程序默认你已经安装好了Ollama。 在运行前需要线安装好Ollama,如何安装请自行搜索 Ollama下载地址: https://ollama.org.cn Ollama模型下载地址&#xf…

Buildroot 添加自定义模块-内置文件到文件系统

目录 概述实现步骤1. 创建包目录和文件结构2. 配置 Config.in3. 定义 cp_bin_files.mk4. 添加源文件install.shmy.conf 5. 配置与编译 概述 Buildroot 是一个高度可定制和模块化的嵌入式 Linux 构建系统,适用于从简单到复杂的各种嵌入式项目. buildroot的源码中bui…

音视频入门基础:RTP专题(12)——RTP中的NAL Unit Type简介

一、引言 RTP封装H.264时,RTP对NALU Header的nal_unit_type附加了扩展含义。 由《音视频入门基础:H.264专题(4)——NALU Header:forbidden_zero_bit、nal_ref_idc、nal_unit_type简介》可以知道,nal_unit…

智慧园区后勤单位消防安全管理:安全运营和安全巡检

//智慧园区消防管理困境大曝光 智慧园区,听起来高大上,但消防管理却让人头疼不已。各消防子系统各自为政,像一座座孤岛,信息不共享、不协同。 消防设施管理分散,不同区域、企业的设备标准不一样,维护情况…

RAG(检索增强生成)原理、实现与评测方法探讨

RAG是什么? 看一下RAG的英文全称:Retrieval-Augmented Generation,建索、增强、生成;一句话串起来就是通过检索增强模型的生成,是的,这就是RAG。 RAG怎么做? 目前比较通用的套路是这样的&#x…

表单制作代码,登录动画背景前端模板

炫酷动效登录页 引言 在网页设计中,按钮是用户交互的重要元素之一。一个炫酷的按钮特效不仅能提升用户体验,还能为网页增添独特的视觉吸引力。今天,我们将通过CSS来实现一个“表单制作代码,登录动画背景前端模板”。该素材呈现了数据符号排版显示出人形的动画效果,新颖有…

HBuilder X安装教程(2025版)

一,官网下载最新包: 官网链接:HBuilderX-高效极客技巧 等待工具包,下载好。 二,安装打开工具: 把HBuilderX压缩包进行压缩,然后打开压缩后的文件夹

【算法系列】希尔排序算法

文章目录 希尔排序算法:一种高效的排序方法一、基本思想二、实现步骤1. 初始化增量2. 分组与排序3. 缩小增量4. 最终排序 三、代码实现四、增量序列的选择1. Shell增量序列2. Hibbard增量序列3. Sedgewick增量序列 五、时间复杂度六、总结 希尔排序算法:…

VMware虚拟机Mac版安装Win10系统

介绍 Windows 10是由美国微软公司开发的应用于计算机和平板电脑的操作系统,于2015年7月29日发布正式版。系统有生物识别技术、Cortana搜索功能、平板模式、桌面应用、多桌面、开始菜单进化、任务切换器、任务栏的微调、贴靠辅助、通知中心、命令提示符窗口升级、文…

android keystore源码分析

架构 Android Keystore API 和底层 Keymaster HAL 提供了一套基本的但足以满足需求的加密基元,以便使用访问受控且由硬件支持的密钥实现相关协议。 Keymaster HAL 是由原始设备制造商 (OEM) 提供的动态加载库,密钥库服务使用它来提供由硬件支持的加密服…

视频字幕识别和翻译

下载的视频很多不是汉语的,我们需要用剪映将语音识别出来作为字幕压制到视频中去。 剪映6.0以后语音识别需要收费,但是低版本还是没有问题。 如果想要非汉语字幕转成中文,剪映低版本不提供这样功能。但是,用剪映导出识别字幕&am…

Rust语言基础知识详解【一】

1.在windows上安装Rust Windows 上安装 Rust 需要有 C 环境,以下为安装的两种方式: 1. x86_64-pc-windows-msvc(官方推荐) 先安装 Microsoft C Build Tools,勾选安装 C 环境即可。安装时可自行修改缓存路径与安装路…

mapbox基础,使用geojson加载fill-extrusion三维填充图层

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️fill-extrusion三维填充图层样式二、�…

用Python3脚本实现Excel数据到TXT文件的智能转换:自动化办公新姿势

文章目录 用Python3实现Excel数据到TXT文件的智能转换:自动化办公新姿势场景应用:为什么需要这种转换?技术解析:代码实现详解核心代码展示改进点说明 实战演练:从Excel到TXT的完整流程准备数据示例(data.xl…

llaMa模型的创新

LLaMa介绍 LLaMa是基于transformer encoder的生成式模型。 目前有:LLAMA, LLAMA2, LLAMA3 三个大的版本 论文 LLAMA 2: Open Foundation and Fine-Tuned Chat Models: https://arxiv.org/pdf/2307.09288 LLAMA 3: The Llama 3 Herd of Models https…

神经网络 - 激活函数(Sigmoid 型函数)

激活函数在神经元中非常重要的。为了增强网络的表示能力和学习能力,激活函数需要具备以下几点性质: (1) 连续并可导(允许少数点上不可导)的非线性函数。可导的激活函数可以直接利用数值优化的方法来学习网络参数. (2) 激活函数及其导函数要尽可能的简单&#xff0…

PINN求解固体力学问题——论文加代码

PINN求解固体力学问题——论文加代码 1. 训练2. 可视化论文:Physics-Informed Deep Learning and its Application in Computational Solid and Fluid Mechanics 基本问题: 网格: 1. 训练 # %load Plane_Stress_W-PINNs.py """ Forward Problem for Plan…

ktransformers 上的 DeepSeek-R1 671B open-webui

ktransformers 上的 DeepSeek-R1 671B open-webui 一、下载GGUF模型1. 创建目录2. 魔塔下载 DeepSeek-R1-Q4_K_M3. 安装显卡驱动和cuda4. 显卡 NVIDIA GeForce RTX 4090 二、安装ktransformers1. 安装依赖2. 安装uv工具链3. 下载源码4. 创建python虚拟环境 三、编译ktransforme…