业务中对批量插入数据的一些场景思考

批量插入或者更新某些数据

场景描述:当我们遇到需要批量插入或者更新的数据时候 解决方案:

  1. 建立复合唯一索引,gorm是使用关键字uniqueIndex,这一步是为了使用数据库的ON DUPLICATE KEY UPDATE功能,有的数据库不支持这类功能

ON DUPLICATE KEY UPDATE 是 MySQL 中的一个特性,用于在插入数据时处理主键或唯一索引冲突。当你尝试插入一行数据,而这行数据的主键或唯一索引与已有的数据冲突时,MySQL 会返回一个错误。但是,如果你使用了 ON DUPLICATE KEY UPDATE 子句,MySQL 就会更新已有的数据,而不是返回一个错误。

go 复制代码
type WordItem struct {
    gorm.Model
    RecordID  uint   `gorm:"primaryKey;uniqueIndex:idx_record_word"` // 外键,关联到Record的ID
    Word      string `gorm:"type:varchar(255);uniqueIndex:idx_record_word"`
    Status    int
    Timestamp int64
}
  1. 开启事务,然后新建一个切片,类型为要批量保存的数据类型,然后新建worditem对象

    go 复制代码
    	// 遍历 dataList 中的 RecordList
    	for _, recordList := range dataList.RecordList {
    		// 对于每个 recordList,创建一个新的 WordItem 对象
    		wordItem := scanpen.WordItem{
    			RecordID:  record.ID,
    			Word:      recordList.Word,
    			Status:    recordList.Status,
    			Timestamp: recordList.Timestamp,
    		}
    		// 使用原生 SQL 语句插入或更新 WordItem
    		sql := `INSERT INTO scanpan_record_item (RecordID, Word, Status, Timestamp, CreatedAt, UpdatedAt) VALUES (?, ?, ?, ?, NOW(), NOW())
                        ON DUPLICATE KEY UPDATE Status = VALUES(Status), Timestamp = VALUES(Timestamp), UpdatedAt = NOW()`
    		if err := tx.Exec(sql, wordItem.RecordID, wordItem.Word, wordItem.Status, wordItem.Timestamp).Error; err != nil {
    			tx.Rollback()
    			return err
    		}
    		// 将 WordItem 添加到 Record 的 WordItems 列表中
    		record.WordItems = append(record.WordItems, wordItem)
    	}
    	// 保存 Record 到数据库
    	if err := tx.Save(&record).Error; err != nil {
    		tx.Rollback()
    		return err
    	}

这段代码的主要目的是将 `dataList.RecordList` 中的每个 recordList 项作为一个新的 WordItem 对象插入到 scanpan_record_item 数据库表中。如果 scanpan_record_item 表中已经存在相同 RecordIDWord 的项,那么这个项的 StatusTimestampUpdatedAt 字段会被更新。

以下是这段代码的详细解释:

  1. for _, recordList := range dataList.RecordList { ... }:这是一个 for-range 循环,用于遍历 dataList.RecordList 列表中的每个元素。每次循环,recordList 都会被设置为列表中的一个元素。

  2. wordItem := scanpen.WordItem{ ... }:这行代码创建了一个新的 WordItem 对象,其字段值从 recordList 中获取。

  3. sql := INSERT INTO scanpan_record_item ...``:这行代码定义了一个 SQL 语句,用于插入或更新 WordItem。这个 SQL 语句使用了 MySQL 的 ON DUPLICATE KEY UPDATE 特性,如果尝试插入的 RecordIDWord 与已有的数据冲突,这个 SQL 语句会更新这个 RecordIDWord 对应的 StatusTimestamp

  4. if err := tx.Exec(sql, ...).Error; err != nil { ... }:这行代码执行了上面定义的 SQL 语句。如果 SQL 语句执行失败,这行代码会回滚事务并返回错误。

  5. record.WordItems = append(record.WordItems, wordItem):这行代码将新创建的 WordItem 添加到 RecordWordItems 列表中。

这段代码的写法主要是为了处理 RecordList 中可能存在的重复项。通过使用 ON DUPLICATE KEY UPDATE,这段代码可以在插入新的 WordItem 时自动更新已有的 WordItem,而不需要先查询数据库来检查 WordItem 是否已存在。这样可以减少数据库查询,提高代码的效率。

相关推荐
Java水解22 分钟前
MySQL必备基础
后端·mysql
Java水解22 分钟前
Spring AOP原理深度解析:代理模式、JDK动态代理与CGLIB
后端·spring
无限大636 分钟前
为什么显示器分辨率越高越清晰?——从像素到 4K/8K 的视觉革命
后端
阿苟42 分钟前
nginx部署踩坑
前端·后端
ChineHe1 小时前
Gin框架基础篇001_路由与路由组详解
后端·golang·gin
神奇小汤圆1 小时前
深入理解Linux IPIP隧道:原理、配置与实战
后端
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue酒店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
laozhoy11 小时前
深入理解Go语言errors.As方法:灵活的错误类型识别
开发语言·后端·golang
周杰伦_Jay1 小时前
【Go 语言】核心特性、基础语法及面试题
开发语言·后端·golang
czlczl200209251 小时前
Spring Boot 参数校验进阶:抛弃复杂的 Group 分组,用 @AssertTrue 实现“动态逻辑校验”
java·spring boot·后端