gorm批量插入解决方案

简介: gorm批量插入解决方案

我有一个朋友, 最近用gorm发现官方不支持批量插入, 看官方issue 2014年就有人提过这个问题了, 不过现在还不支持


但是问题不大, 官方留出来一个执行原生SQL(db.Exec)的方法来解决这个问题, 而且官方现在在开发v2版本, 在v2版本中就会支持这个功能了


image.png


但是生活还得继续, bug还是得继续写, 本来想在网上找一个公用方法来维持一下生活, 结果竟然没找见!


20200415202812852.png


都是指定单个结构体去插入的


20200415203137638.png


这当然不行了, 写代码的意义不就是为了减轻重复的工作嘛, 既然这样, 就只能自己动手丰衣足食了

20200415203343988.png

下面为生成语句的方法

// 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里面加就行了

如果各位大佬有更好的解决方案希望可以拿出来分享学习一下

20200415202716469.png

目录
相关文章
|
3月前
|
SQL 数据库 索引
gorm普通的增删改查
gorm普通的增删改查
54 0
|
3月前
|
数据库
gorm 事务的使用
gorm 事务的使用
78 0
|
2月前
|
SQL Go 数据库
Go语言之GORM框架(二) ——GORM的单表操作
Go语言之GORM框架(二) ——GORM的单表操作
|
3月前
|
JSON 数据库 数据格式
gorm 自定义数据的使用
gorm 自定义数据的使用
33 0
|
3月前
|
Go
golang使用gorm操作mysql3,数据查询
golang使用gorm操作mysql3,数据查询
|
3月前
|
SQL 数据库
GORM—增
GORM—增
36 0
|
3月前
|
SQL 数据库
GORM—查
GORM—查
40 0
|
10月前
|
关系型数据库 MySQL 数据库
GORM V2 读操作
GORM V2 读操作
32 1
|
10月前
|
SQL 安全 数据库
GORM V2 写操作
GORM V2 写操作
38 0
|
SQL
GORM中使用事务
GORM中使用事务
107 0