gorm如何進行批量插入

gorm目前的穩定版是無法進行批量插入(v2.0已列入開發計劃),那麼我們要如何解決呢?

分析結構

列名獲取

gorm的結構體有固定tag,那麼我們就可以取到列名

當然是通過反射來進行了。

舉個例子: AlbumId int64 gorm:"column:album_id;type:bigint(20)" json:"album_id"

我們可以看到,tag的值是以;爲分隔爲鍵值對,然後鍵值對是以:爲分隔符,那麼這樣,我們可以很輕鬆的取到列名。

func GetColumnNameObj(obj interface{}) []string {
	fieldNum := reflect.TypeOf(obj).NumField()
	fieldType := reflect.TypeOf(obj)
	var fieldsName []string
	for i := 0; i < fieldNum; i++ {
		tagValue := fieldType.Field(i).Tag.Get("gorm")
		for _, name := range strings.Split(tagValue, ";") {
			if strings.Index(name, "column") == -1 {
				continue
			}
			fieldsName = append(fieldsName, strings.Replace(name, "column:", "", 1))
		}
		fieldsName = append(fieldsName, tagValue)
	}

	return fieldsName
}

值獲取

既然我們能通過反射獲取列名,那麼獲取值當然也是easy.

func GetColumnValueObj(obj interface{}) []string {
	fieldNum := reflect.TypeOf(obj).NumField()
	fieldType := reflect.TypeOf(obj)
	var fieldsValue []string
	
	for i := 0; i < fieldNum; i++ {
		fName := fieldType.Field(i).Type.Name()
		// 獲取字段類型
		if fName == "string" {
			fieldsValue = append(fieldsValue, "string")
		} else if strings.Index(fName, "uint") != -1 {
			fieldsValue = append(fieldsValue, "uint")
		} else if strings.Index(fName, "int") != -1 {
			fieldsValue = append(fieldsValue, "int")
		}
	
	}

	return fieldsValue
}

當然,我們需要處理更多的類型,我這裏只處理了通用的(u)int64和string。

sql封裝

既然我們都知道了列名,值,那剩下的東西就簡單多了。

拼接sql

func BuildSql(columns []string, lenValues int, table Tabler) (insertSql string) {
	fieldNames := strings.Join(columns, ",")
	lenColumns := len(columns)
	var builder strings.Builder
	if lenValues%lenColumns == 0 {
		//長度驗證
		var i = 0

		for ; i < lenValues/lenColumns; i++ {
			builder.WriteString("(")
			for j := 0; j < lenColumns; j++ {
				if j == lenColumns-1 {
					builder.WriteString("?")
				} else {
					builder.WriteString("?,")
				}
			}
			builder.WriteString("),")
		}
	}
	params := strings.TrimRight(builder.String(), ",") + ";"
	insertSql = fmt.Sprintf("insert into `%s` (%s) values %s", table.TableName(), fieldNames, params)
	return
}

接下來就只剩下執行了

整體代碼如下:

func BatchInsertGromStruct(objs []Tabler) {
	if len(objs) == 0 {
		return
	}
	//獲取列名
	columns := GetColumnNameObj(objs[0])
	//獲取值
	values := GetColumnValueObj(objs)
	//封裝sql
	sql := BuildSql(columns, len(values), objs[0])
	//執行
	GetOrm().Exec(sql, values...)
}

總結

其他ORM也大同小異可以使用此方式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章