首页 > 数据库 >理解在同一数据库连接上并发发起多个事务的问题

理解在同一数据库连接上并发发起多个事务的问题

时间:2024-09-06 17:53:29浏览次数:3  
标签:事务 return err tx 数据库 并发 连接

在现代应用程序中,数据库是数据存储和管理的核心。为了确保数据的一致性和完整性,数据库事务提供了原子性、一致性、隔离性和持久性(ACID)特性。然而,在编写代码时,许多开发者可能会陷入一个常见的误区:在同一个数据库连接(DB 对象)上并发发起多个事务。本文将探讨这个问题的原因、后果及解决方案。

什么是数据库事务?

数据库事务是一组操作的集合,这些操作要么全部成功,要么全部失败。事务的ACID特性确保了数据的有效性和一致性:

  • 原子性:事务中的所有操作要么全部执行成功,要么全部回滚。
  • 一致性:事务的执行将使数据库从一个一致的状态转变到另一个一致的状态。
  • 隔离性:多个事务并发执行时,彼此之间的操作不会相互干扰。
  • 持久性:一旦事务提交,所做的更改将永久保存在数据库中。

并发事务的问题

在同一个数据库连接上并发发起多个事务会导致以下问题:

1. 连接的限制

同一个数据库连接通常只能处理一个事务。如果在一个未完成的事务上再次发起新的事务,可能会导致错误或不确定的状态。这是因为数据库连接在处理事务时会被锁定,无法处理其他请求。

这样是不行的,在一个事务中,并发发起多个事务:

err = db.Transaction(func(tx *gorm.DB) (err error) {
		err = goUtils.RunParallelTasksEx(
			func() (err error) {
				// 使用 FOR UPDATE 锁定行
				// 使用悲观锁可以确保在读取库存数据时锁住该行数据,其他事务必须等待当前事务完成才能继续操作。
				if err = tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("id = ?", round.ID).First(&round).Error; err != nil {
					return err
				}

				// 修改状态
				round.SoldCount += int(eventData.Amount)
				err = roundService.UpdateRound(*round, tx)
				if err != nil {
					global.GVA_LOG.Error(fmt.Sprintf("LotteryEventHandler, UpdateRound failed: %v, RoundId:%d", err, eventData.Round))
					return
				}
				return err
			},
			func() (err error) {
				// 扣除用户gold
				err = tgUserService.UpdateGold(tx, tgUser.TelegramId, int(-costingGold), int(tgUser.Gold), "BuyLottery", strconv.Itoa(int(roundOrder.ID)))
				if err != nil {
					global.GVA_LOG.Error(fmt.Sprintf("LotteryEventHandler, UpdateGold failed: %v, User:%d", err, tgUser.ID))
					return
				}
				return
			})

2. 锁竞争

即使不同的事务操作的是不同的表,也可能存在锁竞争的情况。在高并发环境中,多个事务可能会试图锁定同一资源,从而导致等待和超时错误。

3. 数据库事务的原子性

事务的原子性要求所有操作要么成功,要么失败。在同一连接上同时发起多个事务会使这一特性无法保障,导致数据的不一致性和潜在错误。

解决方案

1. 使用连接池

连接池可以有效管理数据库连接。通过为每个并发事务分配不同的连接,可以避免事务之间的干扰。在大多数现代数据库驱动和ORM中,都支持连接池的功能。

示例代码

以下是一个使用连接池的基本示例:

go
db, err := gorm.Open("mysql", "your-dsn")
if err != nil {
    log.Fatal(err)
}

// 使用连接池并发执行事务
go func() {
    tx := db.Begin()
    defer tx.Rollback()

    // 执行操作
    if err := tx.Create(&entity1).Error; err != nil {
        return
    }

    tx.Commit()
}()

go func() {
    tx := db.Begin()
    defer tx.Rollback()

    // 执行另一个操作
    if err := tx.Create(&entity2).Error; err != nil {
        return
    }

    tx.Commit()
}()

2. 串行化操作

如果在特定情况下必须在同一连接上执行事务,建议串行化操作,确保按顺序完成每个事务,避免并发执行。

3. 实现重试机制

在捕获到由于并发导致的错误时,可以设计重试机制,稍后重试操作,以提高系统的健壮性。

总结

在同一数据库连接上并发发起多个事务是一个常见的误区,可能导致数据不一致、错误和性能问题。通过使用连接池、串行化操作以及实现重试机制,可以有效避免这些问题,确保数据库的稳定性和应用程序的可靠性。理解数据库事务的工作原理和正确处理并发操作是开发高效、可靠应用程序的关键。

标签:事务,return,err,tx,数据库,并发,连接
From: https://www.cnblogs.com/zhanchenjin/p/18400736

相关文章

  • 在全连接层中进行批量数据并行执行
    在全连接层中进行批量数据并行执行在全连接网络中,为了增加并发性并减少权重的负载,可以同时处理一批图像(来自多个视频通道),如图11-31所示。图11-31增加并发性并减少权重的负载,可以同时处理一批图像11.2.6特征缓存在流处理中,对输入和结果使用双缓冲区。对于下一次循环,只需切换......
  • 高速背板连接器 249-4214-11V、249-4216-11V、249-4218-11V、249-4219-11V、249-421H-
    系列概述Paladin®HD系列延续了其作为行业领先的高速应用互连解决方案的传统。Paladin®HD2利用与PaladinHD相同的板连接、双轴电缆连接和配对接口实现向后兼容性,提供直接升级到224Gb/sPAM4的途径。分立屏蔽差分对和革命性的电路板技术实现了无与伦比的性能和密度。特性:世界级......
  • pbootcms提示:“未检测到您服务器环境的sqlite3数据库扩展...”
    解决方法主要有两种,需根据具体情况进行选择。 第一种方法是将数据库配置连接驱动改为pdo_sqlite。首先,按照相关提示,把数据库配置连接驱动修改为pdo_sqlite。随后,可依照图文进行操作。具体而言,打开数据库配置文件,即位于/config/database.php的文件。在该文件中,找到'type'这......
  • 云服务器内网穿透连接云手机配置ALAS
    文章目录服务器安装TailscaleNAT网络(无独立IP)云服务器安装Tailscale有固定IP的云服务器安装Tailscale云手机安装Tailscale开启无线网络调试安装TailscaleALAS连接云手机上次写到服务器连接云手机时只说了有独立IP的,但有独立IP的云手机注定还是少数,大部分云手机还......
  • 数据库简单概述
    什么是数据库?数据库(DatabaseDB)是按照数据结构来组织、存储和管理数据的仓库(存储数据的仓库),它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式。数据库有很多种类型,从最简......
  • 【数据库】主从数据库
    主从数据库是指一种数据库架构,其中一个数据库作为主数据库,负责处理所有的写操作和大部分的读操作,其他一个或多个数据库作为从数据库,从主数据库复制数据并处理读操作。这种架构的核心优点包括负载均衡、数据冗余、读写分离、提高系统的可扩展性。负载均衡通过分散读操作到从数据库......
  • ORCLE数据库语言设置原因查询不出数据的问题解决
    问题现象:oracle数据库视图中存在数据,但是jdbc查询视图查询不出来,后发现视图中有根据默认语言的过滤,如下图: 客户端查询环境语言为 web服务器查询环境语言为US,所以数据查询不出来。解决方案:修改应用端的NLS_LANG的配置与SQL保持一致linux执行下面代码exportNLS_LANG="......
  • Springboot高校党务系统010c1程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统功能:党务老师,党务信息,学生,党员,入党申请,党团活动,党费收缴开题报告内容一、项目背景与意义在新时代背景下,高校党务工作面临着新的机遇与挑战。传统的......
  • Springboot高校爱心服务网站4rz3n(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景随着高等教育的普及和社会对公益事业的日益重视,高校作为知识传播与文化传播的重要阵地,其师生群体拥有强烈的社会责任感和奉献精神。然......
  • 【IEEE出版,IEEE Xplore等多数据库检索】第五届智能设计国际会议(ICID 2024,10月25-27)
    2020年智能设计国际会议(ICID2020)于2020年12月11-13日在西安召开,第二届智能设计国际会议(ICID2021)纳入“欧亚经济论坛—丝绸之路国际创新设计周”系列活动,于2021年10月19日在西安召开,第三届智能设计国际会议(ICID2022)于2022年10月21-23日在西安召开。第四届智能设计国......