使用Gorm AutoMigrate导入CSV时如何避免重复邮箱数据插入?
实现方案
1. 调整模型结构,添加带条件的唯一索引
给Emails字段添加带过滤条件的唯一索引,仅对非空邮箱做唯一性约束,空字符串不受唯一规则限制:
type User struct { // 注意:gorm.Model已自带uint类型的ID、CreatedAt等字段,和你自定义的int64 ID会产生冲突,建议二选一保留 gorm.Model // ID int64 `csv:"_" db:"id"` FirstName string `csv:"First name" db:"first_name"` LastName string `csv:"Last name" db:"last_name"` // 仅非空邮箱走唯一约束 Emails string `csv:"Emails" db:"emails" gorm:"uniqueIndex:idx_unique_email,where:emails != ''"` }
执行AutoMigrate时会自动创建该条件索引,无需手动操作数据库。
2. 插入数据时添加冲突处理逻辑
引入Gorm的冲突处理从句,遇到非空邮箱重复时直接跳过插入,不会抛出异常:
// 首先导入依赖包 import "gorm.io/gorm/clause" func main() { // 补充原有代码缺失的error判断 file, err := os.Open(os.Args[1]) if err != nil { panic(err) } defer file.Close() users := []User{} err = gocsv.Unmarshal(file, &users) if err != nil { panic(err) } db, err := gorm.Open(postgres.Open("host=xxx.xx.x.x user=database password=password dbname=database port=5432 sslmode=disable")) if err != nil { panic(err) } err = db.AutoMigrate(&User{}) if err != nil { panic(err) } // 插入时添加冲突跳过逻辑 result := db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "emails"}}, // 仅非空邮箱触发冲突校验 Where: clause.Where{ Exprs: []clause.Expression{clause.Neq{Column: "emails", Value: ""}}, }, DoNothing: true, }).Create(&users) if result.Error != nil { panic(result.Error) } // 可通过RowsAffected查看实际成功插入的行数 fmt.Printf("成功插入%d条数据\n", result.RowsAffected) }
注意事项
- 如果数据库中已经存在
users表且有重复的非空邮箱数据,执行AutoMigrate时会因为索引创建失败报错,需要先清理历史重复数据再执行迁移 - 空邮箱字段不受唯一约束限制,可正常插入多条记录,完全匹配你的需求
内容的提问来源于stack exchange,提问作者Benk I
相关产品推荐
相关产品推荐

