聊聊gorm的CreateInBatches

.container .card .information strong · · 1062 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本文主要研究一下gorm的CreateInBatches

CreateInBatches

gorm.io/gorm@v1.20.11/finisher_api.go

// CreateInBatches insert the value in batches into database
func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) {
    reflectValue := reflect.Indirect(reflect.ValueOf(value))

    switch reflectValue.Kind() {
    case reflect.Slice, reflect.Array:
        var rowsAffected int64
        tx = db.getInstance()
        tx.AddError(tx.Transaction(func(tx *DB) error {
            for i := 0; i < reflectValue.Len(); i += batchSize {
                ends := i + batchSize
                if ends > reflectValue.Len() {
                    ends = reflectValue.Len()
                }

                subtx := tx.getInstance()
                subtx.Statement.Dest = reflectValue.Slice(i, ends).Interface()
                subtx.callbacks.Create().Execute(subtx)
                if subtx.Error != nil {
                    return subtx.Error
                }
                rowsAffected += subtx.RowsAffected
            }
            return nil
        }))
        tx.RowsAffected = rowsAffected
    default:
        tx = db.getInstance()
        tx.Statement.Dest = value
        tx.callbacks.Create().Execute(tx)
    }
    return
}
CreateInBatches会根据batchSize来分配进行create,但是他们是在同一个事务的,其rowsAffected是每个批次的rowsAffected的累加

AddError

gorm.io/gorm@v1.20.11/gorm.go

// AddError add error to db
func (db *DB) AddError(err error) error {
    if db.Error == nil {
        db.Error = err
    } else if err != nil {
        db.Error = fmt.Errorf("%v; %w", db.Error, err)
    }
    return db.Error
}
tx.AddError方法在db.Error为nil时直接更新为err;不为nil时判断err是否为nil,不为nil时才更新为err

CommitOrRollbackTransaction

gorm.io/gorm@v1.20.11/callbacks/transaction.go

func CommitOrRollbackTransaction(db *gorm.DB) {
    if !db.Config.SkipDefaultTransaction {
        if _, ok := db.InstanceGet("gorm:started_transaction"); ok {
            if db.Error == nil {
                db.Commit()
            } else {
                db.Rollback()
            }
            db.Statement.ConnPool = db.ConnPool
        }
    }
}
CommitOrRollbackTransaction方法会判断db.Error,如果不为nil则执行db.Rollback()

实例

func createInBatchesDemo(db *gorm.DB) {
    entities := []DemoEntity{
        {
            Name: "coco",
        },
        {
            Name: "bear",
        },
    }
    result := db.Debug().CreateInBatches(&entities, 1)
    b, _ := json.Marshal(entities)
    log.Println("data:", string(b))
    log.Println("result.RowsAffected:", result.RowsAffected, "result.Error:", result.Error)
}

输出

2021/01/16 22:28:55 /demo.go:71
[0.384ms] [rows:1] INSERT INTO `demo_entities` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ("2021-01-16 22:28:55.774","2021-01-16 22:28:55.774",NULL,"coco")

2021/01/16 22:28:55 /demo.go:71
[0.055ms] [rows:1] INSERT INTO `demo_entities` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ("2021-01-16 22:28:55.774","2021-01-16 22:28:55.774",NULL,"bear")
2021/01/16 22:28:55 data: [{"ID":7,"CreatedAt":"2021-01-16T22:28:55.7743+08:00","UpdatedAt":"2021-01-16T22:28:55.7743+08:00","DeletedAt":null,"Name":"coco"},{"ID":8,"CreatedAt":"2021-01-16T22:28:55.774794+08:00","UpdatedAt":"2021-01-16T22:28:55.774794+08:00","DeletedAt":null,"Name":"bear"}]
2021/01/16 22:28:55 result.RowsAffected: 2 result.Error: <nil>

小结

gorm的CreateInBatches允许用户自定义batchSize,它会根据batchSize来分配进行create,但是他们是在同一个事务的,其rowsAffected是每个批次的rowsAffected的累加。

doc


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:.container .card .information strong

查看原文:聊聊gorm的CreateInBatches

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1062 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传