MySql操作指南5--事务与并发控制

数据库事务是保障数据一致性和可靠性的重要手段,并发控制则在多用户环境下确保数据的正确性。风云今天详细探讨数据库事务的管理、并发访问的最佳实践,乐观锁与悲观锁的应用,以及Golang 中的事务实现、并发访问的最佳实践,通过合理设计事务和锁机制,可以在高并发场景下有效保障数据的一致性和系统性能。

1、数据库事务管理

事务是一个操作序列,具有以下四个特性(ACID):

原子性(Atomicity):事务中的操作要么全部完成,要么全部回滚。

一致性(Consistency):事务前后,数据库保持一致性状态。

隔离性(Isolation):事务之间相互隔离,避免相互干扰。

持久性(Durability):事务完成后,其对数据库的更改永久生效。

2、在 Golang 中实现事务

 示例:事务的基本操作

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// 数据库连接
	dsn := "user:password@tcp(127.0.0.1:3306)/testdb" // dsn格式

	db, err := sql.Open("mysql", dsn) // 打开数据库连接

	if err != nil { // 如果连接失败,则输出错误信息并退出程序
		log.Fatal(err)
	}

	defer db.Close() // 关闭数据库连接

	// 开启事务
	tx, err := db.Begin() // 开启事务

	if err != nil {
		log.Fatal(err)
	}

	// 执行操作
	_, err = tx.Exec("INSERT INTO accounts (id, balance) VALUES (?, ?)", 1, 100) // 执行操作

	if err != nil { // 如果执行失败,则回滚事务并输出错误信息并退出程序
		tx.Rollback() // 回滚事务

		log.Fatal(err)
	}

	_, err = tx.Exec("UPDATE accounts SET balance = balance - 50 WHERE id = ?", 1) // 执行操作

	if err != nil { // 如果执行失败,则回滚事务并输出错误信息并退出程序
		tx.Rollback() // 回滚事务

		log.Fatal(err)
	}

	// 提交事务
	err = tx.Commit()

	if err != nil { // 如果提交失败,则回滚事务并输出错误信息并退出程序

		log.Fatal(err)

	}

	fmt.Println("Transaction completed successfully")
}

3 事务的隔离级别

MySQL 提供四种事务隔离级别:

  1. 读未提交(Read Uncommitted):事务可以读取其他未提交事务的数据,可能导致脏读。
  2. 读已提交(Read Committed):事务只能读取已提交的数据,避免脏读。
  3. 可重复读(Repeatable Read):同一事务中多次读取数据一致,避免不可重复读(MySQL 默认级别)。
  4. 可串行化(Serializable):完全隔离,事务逐一执行,避免幻读。

设置事务隔离级别

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

在 Golang 中可以通过 SET 语句设置隔离级别:

tx.Exec("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE")

4、并发访问的最佳实践

在并发环境中,事务之间可能发生以下冲突:

  • 脏读(Dirty Read):一个事务读取了另一个未提交事务的数据。
  • 不可重复读(Non-repeatable Read):同一事务中多次读取结果不一致。
  • 幻读(Phantom Read):事务中新增或删除的记录导致结果变化。

以下是一些避免冲突的最佳实践:

5、使用事务管理并发

事务能够隔离并发访问,保证数据一致性。结合合适的隔离级别,可以避免大多数并发问题。

使用锁机制

行锁和表锁

  • 行锁:锁定某一行数据,适用于高并发场景。
  • 表锁:锁定整个表,避免全表修改导致的数据不一致问题。

LOCK TABLES accounts WRITE;UPDATE accounts SET balance = balance - 50 WHERE id = 1;

UNLOCK TABLES;

在 Golang 中,利用事务和条件语句实现锁机制:

tx.Exec("SELECT * FROM accounts WHERE id = ? FOR UPDATE", 1)

6、乐观锁与悲观锁

6.1 乐观锁

乐观锁通过检查版本号或时间戳,确保并发访问不会冲突。

乐观锁实现

SELECT version FROM accounts WHERE id = 1;UPDATE accounts SET balance = balance - 50, version = version + 1 WHERE id = 1 AND version = ?;

Golang 示例

func updateBalanceWithOptimisticLock(db *sql.DB, id int, amount int) error { // 乐观锁
	var version int

	err := db.QueryRow("SELECT version FROM accounts WHERE id = ?", id).Scan(&version) // 查询账户的版本号

	if err != nil { // 如果查询失败,则输出错误信息并退出程序
		return err
	}

	result, err := db.Exec("UPDATE accounts SET balance = balance - ?, version = version + 1 WHERE id = ? AND version = ?", amount, id, version) // 更新账户的余额和版本号

	if err != nil {
		return err
	}

	rowsAffected, err := result.RowsAffected() // 获取受影响的行数

	if err != nil {
		return err
	}

	if rowsAffected == 0 { // 如果受影响的行数为0,则说明版本号不一致,返回错误信息
		return fmt.Errorf("transaction conflict, try again")
	}

	return nil
}

6.2 悲观锁

悲观锁假定冲突必然发生,在操作前加锁以避免冲突。

悲观锁实现

SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

Golang 示例

func updateBalanceWithPessimisticLock(db *sql.DB, id int, amount int) error { // 悲观锁
	tx, err := db.Begin() // 开启事务

	if err != nil { // 如果开启事务失败,则输出错误信息并退出程序
		return err
	}

	_, err = tx.Exec("SELECT * FROM accounts WHERE id = ? FOR UPDATE", id) // 使用FOR UPDATE关键字锁定记录

	if err != nil { // 如果锁定记录失败,则输出错误信息并退出程序
		tx.Rollback() // 回滚事务

		return err
	}

	_, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, id) // 更新账户的余额

	if err != nil { // 如果更新记录失败,则回滚事务并返回错误
		tx.Rollback() // 回滚事务

		return err
	}

	return tx.Commit() // 提交事务并返回nil
}

7、应用场景

  • 电子商务系统:订单支付与库存扣减必须确保一致性。
  • 银行转账系统:多账户之间的资金流转需要事务保证。
  • 多人协作编辑系统:利用乐观锁解决并发编辑冲突。

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

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

相关文章

【MySQL索引:B+树与页的深度解析】

文章目录 MySQL索引:B树与页的深度解析1. 索引使用的数据结构——B树1.1 B树介绍1.2 B树的特点1.3 B树和B树的对比 2. MySQL中的页2.1 页的介绍2.2 页主体2.3 页目录2.4 B树在MySQL索引中的应用 MySQL索引:B树与页的深度解析 在MySQL数据库中&#xff0…

改进上一篇博文中的按键驱动读取程序,增加环形缓冲区

引言和具体的问题描述 上一篇博文:https://blog.csdn.net/wenhao_ir/article/details/145225508 中写的读取按键值的程序,如果按键按得很快,会出现前面的按键值被后面的按键值被覆盖的情况,即前面的按键值还没被来得及被读取&…

linux环境下软件安装

Linux环境下安装软件 linux安装tomcatLinux配置多台Tomcat linux 手动安装jdklinux yum安装jdk(openjdk)Nacos 安装下载nacos解压三、启动四、常用命令 git安装yum命令安装通过编译安装git linux安装tomcat 1.安装tomcat 下载tomcat安装包,解压到任意目录&#xff…

自定义提示确认弹窗-vue

最初可运行代码 弹窗组件代码&#xff1a; &#xff08;后来发现以下代码可运行&#xff0c;但打包 typescript 类型检查出错&#xff0c;可打包的代码在文末&#xff09; <template><div v-if"isVisible" class"dialog"><div class&quo…

leetcode707-设计链表

leetcode 707 思路 本题也是用了虚拟头节点来进行解答&#xff0c;这样的好处是&#xff0c;不管是头节点还是中间的节点都可以当成是中间节点来处理&#xff0c;用同一套方法就可以进行处理&#xff0c;而不用考虑太多的边界条件。 下面题目中最主要的实现就是添加操作addA…

LabVIEW桥接传感器配置与数据采集

该LabVIEW程序主要用于配置桥接传感器并进行数据采集&#xff0c;涉及电压激励、桥接电阻、采样设置及错误处理。第一个VI&#xff08;"Auto Cleanup"&#xff09;用于自动清理资源&#xff0c;建议保留以确保系统稳定运行。 以下是对图像中各个组件的详细解释&#…

OpenCV基础:获取子矩阵的几种方式

目录 相关阅读 方法一&#xff1a;使用切片操作 方法二&#xff1a;使用高级索引 方法三&#xff1a;使用条件筛选 方法四&#xff1a;使用 numpy 的 take 函数 相关阅读 OpenCV基础&#xff1a;矩阵的创建、检索与赋值-CSDN博客 OpenCV基础&#xff1a;图像运算-CSDN博客…

深入剖析Java线程安全的集合类:原理、特点与应用

引言&#xff1a;线程安全集合类的重要性 在当今的软件开发领域&#xff0c;多线程编程已经成为了构建高性能、响应式应用的关键技术。随着硬件技术的飞速发展&#xff0c;多核处理器的普及使得程序能够充分利用多个核心的计算能力&#xff0c;从而显著提升运行效率。在多线程环…

Ubuntu 22.04虚拟机安装配置调整(语言输入法字体共享剪切板等等

2025.01.07安装配置Ubuntu 22.04 记一下 快捷键 截屏 在设置-键盘-快捷键查看 跟搜到的不一样…不过shiftprint感觉也够用 安装 用的是VMware 参考&#xff1a;VMware中安装配置Ubuntu&#xff08;2024最新版 超详细&#xff09; 调教&#xff08;&#xff1f; 语言 改了…

vim练级攻略(精简版)

vim推荐配置: curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh 0. 规定 Ctrl-λ 等价于 <C-λ> :command 等价于 :command <回车> n 等价于 数字 blank字符 等价于 空格&#xff0c;tab&am…

VSCode 的部署

一、VSCode部署 (1)、简介 vsCode 全称 Visual Studio Code&#xff0c;是微软出的一款轻量级代码编辑器&#xff0c;免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比Diff、版本管理GIT等特性&…

Nginx在Linux中的最小化安装方式

1. 安装依赖 需要安装的东西&#xff1a; wget​&#xff0c;方便我们下载Nginx的包。如果是在Windows下载&#xff0c;然后使用SFTP上传到服务器中&#xff0c;那么可以不安装这个软件包。gcc g​&#xff0c;Nginx是使用C/C开发的服务器&#xff0c;等一下安装会用到其中的…

如何在vue中渲染markdown内容?

文章目录 引言什么是 markdown-it&#xff1f;安装 markdown-it基本用法样式失效&#xff1f;解决方法 高级配置语法高亮 效果展示 引言 在现代 Web 开发中&#xff0c;Markdown 作为一种轻量级的标记语言&#xff0c;广泛用于文档编写、内容管理以及富文本编辑器中。markdown…

Android 高版本如何获取App安装列表?

有个需求需要获取App内的安装列表,但是现在在高版本Android中,只能获取到一部分App效果,我获取的代码如下: val calendar Calendar.getInstance()val packageManager context.packageManagerval usageStatsManager context.getSystemService(Context.USAGE_STATS_SERVICE) …

第 5 场 算法季度赛

题目&#xff1a; 5.精准难度【算法赛】 - 蓝桥云课 问题描述 小蓝&#xff0c;蓝桥杯命题组的核心人物。今年的他出题灵感爆发&#xff0c;一口气出了 N 道题目&#xff0c;难度系数分别为 A1​,A2​,…,AN​。 只是&#xff0c;这些题目的难度参差不齐&#xff0c;让组委…

对话 TDengine 解决方案中心总经理陈肃:构建技术与市场的桥梁

TD 小T导读 他是大数据领域的杰出专家&#xff0c;拥有超过十项一作发明专利&#xff0c;是中国通信行业标准《大数据 消息中间件技术要求与测试方法》的重要编写者&#xff0c;并凭借数据中间件领域的突出成就荣获 2019 年“CJK OSS Award”。他是腾讯云 TVP 专家和 TGO 鲲鹏会…

rabbitmq安装延迟队列

在RabbitMQ中&#xff0c;延迟队列是一种特殊的队列类型。当消息被发送到此类队列后&#xff0c;不会立即投递给消费者&#xff0c;而是会等待预设的一段时间&#xff0c;待延迟期满后才进行投递。这种队列在多种场景下都极具价值&#xff0c;比如可用于处理需要在特定时间触发…

GitLab集成Jira

GitLab与Jira集成的两种方式 GitLab 提供了两种 Jira 集成&#xff0c;即Jira议题集成和Jira开发面板集成&#xff0c;可以配置一个或者两个都配置。 具体集成步骤可以参考官方文档Jira 议题集成&#xff08;极狐GitLab文档&#xff09;和Jira 开发面板集成&#xff08;极狐G…

【正则表达式】从0开始学习正则表达式

正则表达式&#xff08;英语&#xff1a;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09; 一、推荐学习网站 正则表达式 – 语法 | 菜鸟教程 正则表达式30分钟入门教程 | 菜鸟教程 编程胶囊-打造学习编程的最好系统 二、必知必记 2.1 元字符…

【docker踩坑记录】

docker踩坑记录 踩坑记录(持续更新中.......)docker images 权限问题 踩坑记录(持续更新中…) docker images 权限问题 permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.s…