Go语言工具箱--Gorm获取新增记录自增主键,使用NewScope还是降级处理?
大漠胡萝卜 · · 4149 次点击 · · 开始浏览默认情况下我们在创建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
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
默认情况下我们在创建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
复制代码欢迎关注公号:程序员的金融圈
一个探讨技术,金融,赚钱的小圈子,为你提供最有味道的内容!