默认情况下我们在创建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
复制代码
欢迎关注公号:程序员的金融圈
一个探讨技术,金融,赚钱
的小圈子,为你提供最有味道
的内容!
有疑问加站长微信联系(非本文作者)