我有一个朋友, 最近用gorm发现官方不支持批量插入, 看官方issue 2014年就有人提过这个问题了, 不过现在还不支持
但是问题不大, 官方留出来一个执行原生SQL(db.Exec)的方法来解决这个问题, 而且官方现在在开发v2版本, 在v2版本中就会支持这个功能了
但是生活还得继续, bug还是得继续写, 本来想在网上找一个公用方法来维持一下生活, 结果竟然没找见!
都是指定单个结构体去插入的
这当然不行了, 写代码的意义不就是为了减轻重复的工作嘛, 既然这样, 就只能自己动手丰衣足食了
下面为生成语句的方法
// GetBranchInsertSql 获取批量添加数据sql语句 func GetBranchInsertSql(objs []interface{}, tableName string) string { if len(objs) == 0 { return "" } fieldName := "" var valueTypeList []string fieldNum := reflect.TypeOf(objs[0]).NumField() fieldT := reflect.TypeOf(objs[0]) for a := 0; a < fieldNum; a++ { name := GetColumnName(fieldT.Field(a).Tag.Get("gorm")) // 添加字段名 if a == fieldNum-1 { fieldName += fmt.Sprintf("`%s`", name) } else { fieldName += fmt.Sprintf("`%s`,", name) } // 获取字段类型 if fieldT.Field(a).Type.Name() == "string" { valueTypeList = append(valueTypeList, "string") } else if strings.Index(fieldT.Field(a).Type.Name(), "uint") != -1 { valueTypeList = append(valueTypeList, "uint") } else if strings.Index(fieldT.Field(a).Type.Name(), "int") != -1 { valueTypeList = append(valueTypeList, "int") } } var valueList []string for _, obj := range objs { objV := reflect.ValueOf(obj) v := "(" for index, i := range valueTypeList { if index == fieldNum-1 { v += GetFormatField(objV, index, i, "") } else { v += GetFormatField(objV, index, i, ",") } } v += ")" valueList = append(valueList, v) } insertSql := fmt.Sprintf("insert into `%s` (%s) values %s", tableName, fieldName, strings.Join(valueList, ",")+";") return insertSql } // GetFormatField 获取字段类型值转为字符串 func GetFormatField(objV reflect.Value, index int, t string, sep string) string { v := "" if t == "string" { v += fmt.Sprintf("'%s'%s", objV.Field(index).String(), sep) } else if t == "uint" { v += fmt.Sprintf("%d%s", objV.Field(index).Uint(), sep) } else if t == "int" { v += fmt.Sprintf("%d%s", objV.Field(index).Int(), sep) } return v } // GetColumnName 获取字段名 func GetColumnName(jsonName string) string { for _, name := range strings.Split(jsonName, ";") { if strings.Index(name, "column") == -1 { continue } return strings.Replace(name, "column:", "", 1) } return "" } // BatchCreateModelsByPage 分页批量插入 func BatchCreateModelsByPage(tx *gorm.DB, dataList []interface{}, tableName string) (err error) { if len(dataList) == 0 { return } // 如果超过一百条, 则分批插入 size := 100 page := len(dataList) / size if len(dataList)%size != 0 { page += 1 } for a := 1; a <= page; a++ { var bills = make([]interface{}, 0) if a == page { bills = dataList[(a-1)*size:] } else { bills = dataList[(a-1)*size : a*size] } sql := GetBranchInsertSql(bills, tableName) if err = tx.Exec(sql).Error; err != nil { fmt.Println(fmt.Sprintf("batch create data error: %v, sql: %s, tableName: %s", err, sql, tableName)) return } } return }
最后会返回批量插入的sql语句, 这样一来就舒服多了
因为我的朋友 现在类型主要用到了string, int和uint, 如果有其他类型需要加的话在 获取字段类型和GetFormatFeild里面加就行了
如果各位大佬有更好的解决方案希望可以拿出来分享学习一下