Go语言工具箱--Gorm获取新增记录自增主键,使用NewScope还是降级处理?

大漠胡萝卜 · · 3345 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

默认情况下我们在创建mysql表结构的时候会设置一个自增的主键id,创建好一条记录之后,使用该主键id关联其他的业务。

表结构如下:

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1;
复制代码

Gorm默认提供的Create方法在创建一条数据之后,可以之前的对象中获取,如:

type Tests struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  int64  `json:"age"`
}

mbr := Tests{
	Name: "111",
	Age:  10,
}
err = db.Table("test").Create(&mbr).Error
复制代码

创建之后,能够通过mbr.Id获取自增编号。

但是,使用这种方式有个尴尬的地方,万一Age或者Name字段为空怎么办呢?

如下代码:

type Tests struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  int64  `json:"age"`
}

mbr := Tests{
	Name: "111",
}
err = db.Table("test").Create(&mbr).Error
复制代码

执行的sql语句如下,会给age设置一个默认值0,但是数据库默认值为NULL,0可以是具有业务意义的。

INSERT  INTO `test` (`name`,`age`) VALUES ('111',0)
复制代码

那么如何才能避免没有0的情况发生呢?

有如下三种方法,都是通过model结构提对象的改动实现。

  • 方法一,给结构体增加default字段,sSql语句在拼装的时候就不会设置空值,但是默认值也不会生效,显得累赘。
type Tests struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  int64  `gorm:"default:'0'"json:"age"`
}

mbr := Tests{
	Name: "222",
}
err = db.Table("test").Create(&mbr).Error
复制代码

执行的sql语句:

INSERT  INTO `test` (`name`) VALUES ('222')
复制代码
  • 方法二,修改结构体变量的类型为指针类型
type Tests struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  *int64 `json:"age"`
}

mbr := Tests{
	Name: "111",
}
err = db.Table("test").Create(&mbr).Error
复制代码

执行的sql语句如下,将空指针转化为NULL

INSERT  INTO `test` (`name`,`age`) VALUES ('111',NULL)
复制代码
  • 方法三,使用sql.NullInt64定义字段
type Tests struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  sql.NullInt64
}

mbr := Tests{
	Name: "111",
}
err = db.Table("test").Create(&mbr).Error
复制代码

执行的sql语句和方法二相同。

INSERT  INTO `test` (`name`,`age`) VALUES ('111',NULL)
复制代码

以上三种方法都在一定程度上增加结构体对象的复杂程度,但理想的方式是保持结构体对象的简单直观。

于是,可以采取直接写sql方法,虽然能够实现新增的方法,但是无法获取到插入那一行数据的自增id。

dbRes := db.Table("test").Exec("insert into test (name) values('pengj')")
fmt.Println("value ->",dbRes.Value)
复制代码

看了gorm源码实现之后发现,无论是Create还是Update方法在调用的时候都调用了NewScope方法,于是尝试使用下面的方式:

mbr := Tests{}
db.Table("test").NewScope(mbr).Raw("insert into test (name) values('xm')").Exec()
fmt.Println( mbr)
复制代码

开始以为,数据创建之后的完整数据都会放到mbr中,但是大失所望,mbr对象中还是没有自增主键id

继续看代码,gorm这个orm既然是对底层database/sql的封装,那么如果降级处理,是不是可以解决问题呢?

继续开代码之后,发现了下面的实现方式:

res, err := db.CommonDB().Exec("insert into test (name) values('xm')")
if err != nil {
	panic(err)
}
affectId, _ := res.RowsAffected()
insertId, _ := res.LastInsertId()
fmt.Println("affectId && insertId ", affectId, insertId)
复制代码

最终输出如下结果,解决文章开始提出的问题,insertId也就是表结构中的自增id的值。

affectId && insertId  1 110
复制代码

欢迎关注公号:程序员的金融圈 一个探讨技术,金融,赚钱的小圈子,为你提供最有味道的内容!


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

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

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