常用方法

Insert/Replace/Save

这几个链式操作方法用于数据的写入,并且支持自动的单条或者批量的数据写入,区别如下:

  1. Insert

    使用 INSERT INTO 语句进行数据库写入,如果写入的数据中存在主键或者唯一索引时,返回失败,否则写入一条新数据。

  2. Replace

    使用 REPLACE INTO 语句进行数据库写入,如果写入的数据中存在主键或者唯一索引时,会删除原有的记录,必定会写入一条新记录。

  3. Save

    使用 INSERT INTO 语句进行数据库写入,如果写入的数据中存在主键或者唯一索引时,更新原有数据,否则写入一条新数据。对于部分数据库,例如 PgSQL, SQL server, Oracle 可以使用 OnConflict 方法指定冲突键。

    1. db.Model(table).Data(g.Map{
    2. "id": 1,
    3. "passport": "p1",
    4. "password": "pw1",
    5. }).OnConflict("id").Save()

在部分数据库类型中,并不支持 Replace/Save 方法,具体请参考 链式操作 介绍章节。

这几个方法需要结合 Data 方法使用,该方法用于传递数据参数,用于数据写入/更新等写操作。

InsertIgnore

用于写入数据时如果写入的数据中存在主键或者唯一索引时,忽略错误继续执行写入。该方法定义如下:

  1. func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error)

InsertAndGetId

用于写入数据时并直接返回自增字段的 ID。该方法定义如下:

  1. func (m *Model) InsertAndGetId(data ...interface{}) (lastInsertId int64, err error)

OnDuplicate/OnDuplicateEx

OnDuplicate/OnDuplicateEx 方法需要结合 Save 方法一起使用,用于指定 Save 方法的更新/不更新字段,参数为字符串、字符串数组、 Map。例如:

  1. OnDuplicate("nickname, age")
  2. OnDuplicate("nickname", "age")
  3. OnDuplicate(g.Map{
  4. "nickname": gdb.Raw("CONCAT('name_', VALUES(`nickname`))"),
  5. })
  6. OnDuplicate(g.Map{
  7. "nickname": "passport",
  8. })

其中 OnDuplicateEx 用于排除指定忽略更新的字段,排除的字段需要在写入的数据集合中。

使用示例

示例1,基本使用

数据写入/保存方法需要结合 Data 方法使用,方法的参数类型可以为 Map/Struct/Slice

  1. // INSERT INTO `user`(`name`) VALUES('john')
  2. g.Model("user").Data(g.Map{"name": "john"}).Insert()
  3. // INSERT IGNORE INTO `user`(`uid`,`name`) VALUES(10000,'john')
  4. g.Model("user").Data(g.Map{"uid": 10000, "name": "john"}).InsertIgnore()
  5. // REPLACE INTO `user`(`uid`,`name`) VALUES(10000,'john')
  6. g.Model("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
  7. // INSERT INTO `user`(`uid`,`name`) VALUES(10001,'john') ON DUPLICATE KEY UPDATE `uid`=VALUES(`uid`),`name`=VALUES(`name`)
  8. g.Model("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()

也可以不使用 Data 方法,而给写入/保存方法直接传递数据参数:

  1. g.Model("user").Insert(g.Map{"name": "john"})
  2. g.Model("user").Replace(g.Map{"uid": 10000, "name": "john"})
  3. g.Model("user").Save(g.Map{"uid": 10001, "name": "john"})

数据参数也常用 struct 类型,例如当表字段为 uid/name/site 时:

  1. type User struct {
  2. Uid int `orm:"uid"`
  3. Name string `orm:"name"`
  4. Site string `orm:"site"`
  5. }
  6. user := &User{
  7. Uid: 1,
  8. Name: "john",
  9. Site: "https://goframe.org",
  10. }
  11. // INSERT INTO `user`(`uid`,`name`,`site`) VALUES(1,'john','https://goframe.org')
  12. g.Model("user").Data(user).Insert()

示例2,数据批量写入

通过给 Data 方法输入 Slice 数组类型的参数,用以实现批量写入。数组元素需要为 Map 或者 Struct 类型,以便于数据库组件自动获取字段信息并生成批量操作 SQL

  1. // INSERT INTO `user`(`name`) VALUES('john_1'),('john_2'),('john_3')
  2. g.Model("user").Data(g.List{
  3. {"name": "john_1"},
  4. {"name": "john_2"},
  5. {"name": "john_3"},
  6. }).Insert()

可以通过 Batch 方法指定批量操作中分批写入条数数量(默认是 10),以下示例将会被拆分为两条写入请求:

  1. // INSERT INTO `user`(`name`) VALUES('john_1'),('john_2')
  2. // INSERT INTO `user`(`name`) VALUES('john_3')
  3. g.Model("user").Data(g.List{
  4. {"name": "john_1"},
  5. {"name": "john_2"},
  6. {"name": "john_3"},
  7. }).Batch(2).Insert()

示例3,数据批量保存

批量保存操作与单条保存操作原理是一样的,当写入的数据中存在主键或者唯一索引时将会更新原有记录值,否则新写入一条记录。

oracle, dm, mssql 不支持批量保存。

  1. // INSERT INTO `user`(`uid`,`name`) VALUES(10000,'john_1'),(10001,'john_2'),(10002,'john_3')
  2. // ON DUPLICATE KEY UPDATE `uid`=VALUES(`uid`),`name`=VALUES(`name`)
  3. g.Model("user").Data(g.List{
  4. {"uid":10000, "name": "john_1"},
  5. {"uid":10001, "name": "john_2"},
  6. {"uid":10002, "name": "john_3"},
  7. }).Save()

RawSQL 语句嵌入

gdb.Raw 是字符串类型,该类型的参数将会直接作为 SQL 片段嵌入到提交到底层的 SQL 语句中,不会被自动转换为字符串参数类型、也不会被当做预处理参数。更详细的介绍请参考章节: ORM高级特性-RawSQL。例如:

  1. // INSERT INTO `user`(`id`,`passport`,`password`,`nickname`,`create_time`) VALUES('id+2','john','123456','now()')
  2. g.Model("user").Data(g.Map{
  3. "id": "id+2",
  4. "passport": "john",
  5. "password": "123456",
  6. "nickname": "JohnGuo",
  7. "create_time": "now()",
  8. }).Insert()
  9. // 执行报错:Error Code: 1136. Column count doesn't match value count at row 1

使用 gdb.Raw 改造后:

  1. // INSERT INTO `user`(`id`,`passport`,`password`,`nickname`,`create_time`) VALUES(id+2,'john','123456',now())
  2. g.Model("user").Data(g.Map{
  3. "id": gdb.Raw("id+2"),
  4. "passport": "john",
  5. "password": "123456",
  6. "nickname": "JohnGuo",
  7. "create_time": gdb.Raw("now()"),
  8. }).Insert()