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

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

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

  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 表中已经存在相同 RecordID 和 Word 的项,那么这个项的 Status、Timestamp 和 UpdatedAt 字段会被更新。

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

  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 特性,如果尝试插入的 RecordID 和 Word 与已有的数据冲突,这个 SQL 语句会更新这个 RecordID 和 Word 对应的 Status 和 Timestamp。

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

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

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

相关推荐
程序员海军8 小时前
用了两年多 GPT,我最近开始换模型了,还折腾了个求职避坑 Agent
前端·人工智能·后端
码士集团小青8 小时前
SpringBoot 集成缓存性能之王 Caffeine
spring boot·后端·缓存
excel10 小时前
IndexNow:让搜索引擎更快发现网站更新的主动通知协议
前端·后端·架构
Json____10 小时前
用 FastAPI + Vue3 打造一套完整的在线考试系统:从组卷到阅卷的业务闭环实践
后端·node.js·fastapi·it学习·wwwoop.com
小灰灰搞电子11 小时前
Rust+Slint 实现FTP客户端调试助手源码分享
开发语言·后端·rust
专业程序开发源12 小时前
springboot欧缇蔓月子中心管理系统82697-计算机课程设计、毕业设计
java·spring boot·后端·python·spring·django·课程设计
卷无止境12 小时前
面向arm64桌面客户端开发全景:语言、框架与生态
后端·python
IT_陈寒13 小时前
JavaScript的闭包陷阱,这个坑我躺了三天才爬出来
前端·人工智能·后端
用户83562907805113 小时前
如何使用 Python 对 Excel 数据进行分组和分级显示
后端·python
vx_Biye_Design13 小时前
django房屋租赁推荐系统78455-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·课程设计·express