洞察在数字化转型过程中,信创推动企业有效整合资源,实现低成本、高效率的跨平台小程序运营。
1316
2022-10-11
GO orm 框架GORM学习
1. 介绍
gorm是一个使用Go语言编写的ORM框架。它文档齐全,对开发者友好,支持主流数据库。官方中文文档 安装
go get -u gorm.io/gormgo get -u gorm.io/driver/sqlite
3. 连接MYSQL
GORM 官方支持的数据库类型有:MySQL, PostgreSQL, SQlite, SQL Server,这里只讲常见的MYSQL。其他类型数据库参见官方文档。
3.1 安装mysql依赖
go get -u gorm.io/driver/mysql
3.2 建立连接
a. 默认连接
// 默认连接func ConnectMysqlByDefault(host, port, user, pass, dbname string) (*gorm.DB, error) { // user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local dns := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, dbname) return gorm.Open(mysql.Open(dns), &gorm.Config{})}
b. 自定义配置连接
// 自定义配置连接func ConnectMysqlByCustom(host, port, user, pass, dbname string) (*gorm.DB, error) { // user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local dns := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, dbname) return gorm.Open(mysql.New(mysql.Config{ DSN: dns, DefaultStringSize: 256, // string 类型字段的默认长度 DisableDatetimePrecision: true, //禁用 datetime 精度,MySQL 5.6 之前的数据库不支持 DontSupportRenameIndex: true, //重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引 DontSupportRenameColumn: true, //用change重命名列,MySQL8之前的数据库和 MariaDB 不支持重命名列 SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置 }))}
c. 基于database/sql连接
// 基于database/sql连接,进行二次封装func ConnectMysqlByDatabaseSql(host, port, user, pass, dbname string) (*gorm.DB, error) { dns := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, dbname) db, err := sql.Open("mysql", dns) if err != nil { return nil, err } return gorm.Open(mysql.New(mysql.Config{Conn: db}))}
gorm.Config配置使用,参见官方文档: 什么是模型
模型其实就是标准的结构体(struct),其属性和表结构的字段按照 gorm约定 一一对应。约定如下:
gorm使用ID作为主键,对应表中的id。使用结构体名的蛇形复数 作为表名。对于结构体User,根据约定,其表名为users使用CreatedAt、UpdatedAt 字段追踪创建、更新时间。
gorm 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt,其他结构体直接匿名嵌套即可。
4.2 字段标签
标签名 | 说明 |
| 指定 db 列名 |
| 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如: |
| 指定列大小,例如: |
| 指定列为主键 |
| 指定列为唯一 |
| 指定列的默认值 |
| 指定列为 NOT NULL |
| 指定列为自动增长 |
| 迁移时为字段添加注释 |
| 根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情 |
更多约定,请查看官方文档
4.3 创建用户模型
按照gorm约定创建用户模型,便于后面使用。用户模型如下
// 用户模型type User struct { gorm.Model NickName string `gorm:"type:varchar(20);not null;default:'';comment:昵称"` Age uint8 `gorm:"size:4;comment:年龄"` Phone string `gorm:"type:char(11);index:un_phone;comment:手机号"` MemberNumber string `gorm:"type:varchar(20);index:un_phone;comment:会员编号"` Birthday sql.NullString `gorm:"type:varchar(10);comment:生日"` ActivatedAt sql.NullTime `gorm:"comment:激活时间"`}
5. 迁移
5.1 根据模型生成表结构
根据上面创建的用户模型User,生成对应的表结构
a. 代码
// 自动迁移schema,(根据结构体创建或者更新schema)func GormAutoMigrate(host, port, use, pass, database string) error { // ConnectMysqlByDefault 代码参见上面的: 默认连接 mysqlByDefault, err := ConnectMysqlByDefault(host, port, use, pass, database) if err != nil { return err } // 指定引擎和表备注 err = mysqlByDefault.Set("gorm:table_options", "ENGINE=InnoDB COMMENT='用户表'").AutoMigrate(&User{}) if err != nil { return err } return nil}// 测试迁移func TestAutoMigrate(t *testing.T) { host := "127.0.0.1" use,pass,port,database := "root","root","3306","test" err := gorme.GormAutoMigrate(host, port, use, pass, database) if err != nil { t.Error(err) } fmt.Println("创建表结构完成!")}
b. 生成的表结构如下:
CREATE TABLE `users` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `created_at` datetime(3) DEFAULT NULL, `updated_at` datetime(3) DEFAULT NULL, `deleted_at` datetime(3) DEFAULT NULL, `nick_name` varchar(20) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '昵称', `age` tinyint unsigned DEFAULT NULL COMMENT '年龄', `phone` char(11) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '手机号', `member_number` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '会员编号', `birthday` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '生日', `activated_at` datetime(3) DEFAULT NULL COMMENT '激活时间', PRIMARY KEY (`id`), KEY `idx_users_deleted_at` (`deleted_at`), KEY `un_phone` (`phone`,`member_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户表';
6.CRUD
6.1 初始化客户端
// 定义包内全局变量var mysqlClient *gorm.DB// 初始化mysql客户端func init() { // 连接客户端 host := "127.0.0.1" user, pass, port, database := "root", "root", "3306", "test" databaseSql, _ := gorme.ConnectMysqlByDatabaseSql(host, port, user, pass, database) mysqlClient = databaseSql}
6.2 单条插入
// 保存一条记录func TestAddOne(t *testing.T) { // 初始化结构体 userRow := gorme.User{ NickName: "李四", Age: 18, Phone: "12340000", MemberNumber: "A0001", Birthday: sql.NullString{String: "1991-03-04",Valid: true}, ActivatedAt: sql.NullTime{Time: time.Now(),Valid: true}, } // 传入指针 result := mysqlClient.Create(&userRow) fmt.Println(result) fmt.Println("id: ",userRow.ID) fmt.Println("插入记录错误: ",result.Error) fmt.Println("插入记录的条数: ",result.RowsAffected)}/*** 输出=== RUN TestAddOne&{0xc000184240
6.3 批量插入
// 批量插入func TestBatchInsert(t *testing.T) { // 定义user 切片 userRows := []gorme.User{ {NickName: "路人甲", Age: 20, Phone: "20000000", MemberNumber: "A0002"}, {NickName: "路人乙", Age: 22, Phone: "30000000", MemberNumber: "A0003"}, {NickName: "路人丙", Age: 24, Phone: "40000000", MemberNumber: "A0004"}, } // 保存 result := mysqlClient.Create(&userRows) fmt.Println("插入记录错误: ", result.Error) fmt.Println("插入记录的条数: ", result.RowsAffected) // 打印ID for _, row := range userRows { fmt.Println("插入ID: ", row.ID) }}/** 输出=== RUN TestBatchInsert插入记录错误:
更新插入方式,参见文档: 查询
a. 单条记录: First、Take、Last
First: 获取第一条记录(主键升序)Take: 获取一条记录,没有指定排序字段Last: 获取最后一条记录(主键降序)
// 使用提供的First、Take、Last,查询单条记录func TestGetOne(t *testing.T) { // 定义对应的结构体变量存储结果 var firstUser gorme.User var taskUser gorme.User var lastUser gorme.User var result *gorm.DB // 获取第一条记录(主键升序) SELECT * FROM users ORDER BY id LIMIT 1; result = mysqlClient.First(&firstUser) fmt.Printf("First Result: %+v\n", result.RowsAffected) // 获取一条记录,没有指定排序字段 SELECT * FROM users LIMIT 1; result = mysqlClient.Take(&taskUser) fmt.Printf("Take Result: %+v\n", result.RowsAffected) // 获取最后一条记录(主键降序)SELECT * FROM users ORDER BY id DESC LIMIT 1; result = mysqlClient.Last(&lastUser) fmt.Printf("lastUser Result: %+v\n", result.RowsAffected)}
@注意: 如果表里没有数据,会报错result.Error返回:ErrRecordNotFound,可以使用下面语句检查错误。如果想避免ErrRecordNotFound错误,你可以使用Find,如:db.Limit(1).Find(&user)
// 检查 ErrRecordNotFound 错误errors.Is(result.Error, gorm.ErrRecordNotFound)
b. 多条记录: Find
// 使用Find(默认查询的是检索全部)func TestGetByFind(t *testing.T) { var userList []gorme.User // 指针查询字段 result := mysqlClient.Select("id", "nick_name").Find(&userList) for _, user := range userList { fmt.Printf("id: %d nick_name: %s \n", user.ID,user.NickName) } fmt.Println("查询记录数: ", result.RowsAffected) fmt.Println("查询错误: ", result.Error)}/** 输出=== RUN TestGetByFindid: 2 nick_name: 李四 id: 3 nick_name: 张三 id: 4 nick_name: 路人甲 id: 5 nick_name: 路人乙 id: 6 nick_name: 路人丙 查询记录数: 5查询错误:
c. 条件查询
1. String条件
// 根据String条件查询func TestGetByStringWhere(t *testing.T) { // 定义对应的结构体变量 var user gorme.User var userList []gorme.User var result *gorm.DB // 字符串条件查询一条 result = mysqlClient.Where("nick_name = ?", "张三").First(&user) fmt.Printf("Res1: %v err:%v \n", result.RowsAffected,result.Error) // 字符串条件查询多条 result = mysqlClient.Where("nick_name <> ?", "张三").Find(&userList) fmt.Printf("Res2: %v err:%v \n", result.RowsAffected,result.Error) // 多个条件 result = mysqlClient.Where("nick_name = ? and age >= ?", "张三", 18).First(&user) fmt.Printf("Res3: %v err:%v \n", result.RowsAffected,result.Error)}/** 输出=== RUN TestGetByStringWhereRes1: 1 err:
2. Struct和Map条件
// 根据struct和map 条件查询结果func TestGetByStructAndMapWhere(t *testing.T) { // 定义对应的结构体变量 var user gorme.User var userList []gorme.User var result *gorm.DB // 结构体条件 result = mysqlClient.Where(&gorme.User{NickName: "张三",Age: 18}).First(&user) fmt.Printf("结构体条件: %+v err:%v \n", result.RowsAffected,result.Error) // map条件 result = mysqlClient.Where(map[string]interface{}{"age":18}).Find(&userList) fmt.Printf("map条件: %+v err:%v \n", result.RowsAffected,result.Error) // 主键切片 result = mysqlClient.Where([]int64{2,3,4,5}).Find(&userList) fmt.Printf("主键切片: %+v err:%v \n", result.RowsAffected,result.Error)}/** 输出=== RUN TestGetByStructAndMapWhere结构体条件: 1 err:
@注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值,该字段不会被用于构建查询条件,例如:db.Where(&User{NickName: "张三", Age: 0}).Find(&users) // SELECT * FROM users WHERE name = "张三";
更多查询规则和方法,见: 更新
a. 更新单个字段
// 更新单个字段func TestUpdateColumn(t *testing.T) { var result *gorm.DB // 字符串条件更新 // UPDATE users SET nick_name='张三A', updated_at=当前时间 WHERE nick_name='张三; result = mysqlClient.Model(&gorme.User{}).Where("nick_name = ?", "张三"). Update("nick_name", "张三A") fmt.Printf("条件更新: %+v err:%v \n", result.RowsAffected, result.Error) // 结构体条件更新 // UPDATE users SET age=28, updated_at=当前时间 WHERE member_number='A0001; result = mysqlClient.Model(&gorme.User{}).Where(&gorme.User{MemberNumber: "A0001"}).Update("age",28) fmt.Printf("结构体条件更新: %+v err:%v \n", result.RowsAffected, result.Error)}/** 输出=== RUN TestUpdateColumn条件更新: 1 err:
b. 更新多个字段
// 更新多个字段func TestUpdateMultipleColumn(t *testing.T) { var result *gorm.DB // 使用map updateMap := map[string]interface{}{ "age": 32, "birthday": "1991-01-05", } // UPDATE users SET age=32,birthday='1991-01-05',updated_at=当前时间 WHERE id=6; result = mysqlClient.Model(&gorme.User{}).Where("id = ?", 6).Updates(updateMap) fmt.Printf("使用map结构更新: %+v err:%v \n", result.RowsAffected, result.Error) // 使用结构体(不使用Select) updateUser := gorme.User{ Birthday: sql.NullString{String: "1993-10-10", Valid: true}, Age: 0, } // @注意这里的age=0不会更新到MySQL // UPDATE users SET birthday='1993-09-09',updated_at=当前时间 WHERE id=5; result = mysqlClient.Model(&gorme.User{}).Where("id = ?", 5).Updates(updateUser) fmt.Printf("使用struct结构更新: %+v err:%v \n", result.RowsAffected, result.Error) // 使用结构体(使用Select) updateUser2 := gorme.User{ Birthday: sql.NullString{String: "1993-09-09", Valid: true}, Age: 0, } // UPDATE users SET birthday='1993-09-09',age=0,updated_at=当前时间 WHERE id=4; result = mysqlClient.Model(&gorme.User{}). Select("birthday", "age"). //指定要更新的字段 Where("id = ?", 4).Updates(updateUser2) fmt.Printf("使用struct结构更新2: %+v err:%v \n", result.RowsAffected, result.Error)}
6.6 删除
a. 软删除
// 删除数据func TestSoftDel(t *testing.T) { var result *gorm.DB // 根据主键,删除一条记录 result = mysqlClient.Delete(&gorme.User{},1) fmt.Printf("根据主键删除一条: %+v err:%v \n", result.RowsAffected, result.Error) // 根据主键切片,删除多条记录 result = mysqlClient.Delete(&gorme.User{},[]int64{2,3}) fmt.Printf("根据主键切片删除多条: %+v err:%v \n", result.RowsAffected, result.Error) // 根据条件删除 result = mysqlClient.Where("age = ?",0).Delete(&gorme.User{}) fmt.Printf("根据条件删除: %+v err:%v \n", result.RowsAffected, result.Error)}
执行上面代码后,发现表里面的记录依然存在,而DeletedAt 置为当前时间。原因是user模型中包含了一个 gorm.DeletedAt 字段,它将自动获得软删除的能力!
b. 永久删除
可以使用 Unscoped 永久删除匹配的记录。
// 删除数据(硬删除)func TestStrongDel(t *testing.T) { var result *gorm.DB result = mysqlClient.Unscoped().Delete(&gorme.User{}, 1) fmt.Printf("硬删除: %+v err:%v \n", result.RowsAffected, result.Error)}
6.7 事务
a. 使用Transaction
// 事务使用(Transaction)func TestTransaction(t *testing.T) { err := mysqlClient.Transaction(func(tx *gorm.DB) error { //在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db') // 创建用户记录 user := gorme.User{NickName: "老王", Age: 48} if err := tx.Create(&user).Error; err != nil { // 回滚事务 return err } // 创建用户地址 userAddress := gorme.UserAddress{Uid: user.ID, Province: "北京", City: "北京", Area: "海淀区"} if err := tx.Create(&userAddress).Error; err != nil { // 回滚事务 return err } return nil }) if err != nil { t.Error(err) } fmt.Println("执行完成")}
b. 手动事务
// 手动事务func TestUseManualTx(t *testing.T) { // 用户表 user := gorme.User{NickName: "小丽", Age: 19} // 开启事务 tx := mysqlClient.Begin() // 添加用户 if err := tx.Create(&user).Error; err != nil { // 遇到错误时回滚事务 fmt.Println("添加用户失败: ",err) tx.Rollback() } // 用户地址表 userAddress := gorme.UserAddress{Uid: user.ID, Province: "北京", City: "北京", Area: "昌平区"} // 添加用户地址 if err := tx.Create(&userAddress).Error; err != nil { // 遇到错误时回滚事务 fmt.Println("添加用户地址失败: ",err) tx.Rollback() } // 提交事务 tx.Commit() fmt.Println("执行完成")}
@注意: 在实践中发现,执行时虽然事务失败,但是主键依然递增。具体看下图效果:
7、gorm 反向生成 struct
db2struct --host rdsfjnifbfjnifbo.mysql.rds.aliyuncs.com -d bigbusiness -t customer --package main --struct customer -p -u bigbusiness
db2struct [-H] [-p] [-v] --package pkgName --struct structName --database databaseName --table tableNameOptions:-H, --host= Host to check mariadb status of–mysql_port=3306 Specify a port to connect to-t, --table= Table to build struct from-d, --database=nil Database to for connection-u, --user=user user to connect to database-v, --verbose Enable verbose output–package= name to set for package–struct= name to set for struct–json Add json annotations (default)–no-json Disable json annotations–gorm Add gorm annotations (tags)–guregu Add guregu null types–target= Save file path-p, --password= Mysql password-h, --help Show usage message–version Show version
8、参考操作
插入
//插入数据func (user *User) Insert() { //这里使用了Table()函数,如果你没有指定全局表名禁用复数,或者是表名跟结构体名不一样的时候 //你可以自己在sql中指定表名。这里是示例,本例中这个函数可以去除。 db.Table("user").Create(user)}
更新
//注意,Model方法必须要和Update方法一起使用//使用效果相当于Model中设置更新的主键key(如果没有where指定,那么默认更新的key为id),Update中设置更新的值//如果Model中没有指定id值,且也没有指定where条件,那么将更新全表//相当于:update user set name='xiaoming' where id=1;user := User{Id: 1,Name:"xiaoming"}db.Model(&user).Update(user)//注意到上面Update中使用了一个Struct,你也可以使用map对象。//需要注意的是:使用Struct的时候,只会更新Struct中这些非空的字段。//对于string类型字段的"",int类型字段0,bool类型字段的false都被认为是空白值,不会去更新表//下面这个更新操作只使用了where条件没有在Model中指定id//update user set name='xiaohong' wehre sex=1db.Model(&User{}).Where("sex = ?",1).Update("name","xiaohong")
如果你想手动将某个字段set为空值, 可以使用单独选定某些字段的方式来更新:
user := User{Id: 1}db.Model(&user).Select("name").Update(map[string]interface{}{"name":"","age":0})
忽略掉某些字段:
当你的更新的参数为结构体,而结构体中某些字段你又不想去更新,那么可以使用Omit方法过滤掉这些不想update到库的字段:
user := User{Id: 1,Name:"xioaming",Age:12}db.Model(&user).Omit("name").Update(&user)
删除
//delete from user where id=1;user := User{Id: 1}db.Delete(&user)//delete from user where id > 11;db.Delete(&User{},"id > ?",11)
事务
func CreateAnimals(db *gorm.DB) err { tx := db.Begin() // 注意,一旦你在一个事务中,使用tx作为数据库句柄 if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil { tx.Rollback() return err } if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil { tx.Rollback() return err } tx.Commit() return nil}
查询:
func (user *User) query() (u []User) { //查询所有记录 db.Find(&u) //Find方法可以带 where 参数 db.Find(&u,"id > ? and age > ?",2,12) //带where 子句的查询,注意where要在find前面 db.Where("id > ?", 2).Find(&u) // where name in ("xiaoming","xiaohong") db.Where("name in (?)",[]string{"xiaoming","xiaohong"}).Find(&u) //获取第一条记录,按照主键顺序排序 db.First(&u) //First方法可以带where 条件 db.First(&u,"where sex = ?",1) //获取最后一条记录,按照主键顺序排序 //同样 last方法也可以带where条件 db.Last(&u) return u}
注意:方法中带的&u表示是返回值用u这个对象来接收。
上面的查询都将返回表中所有的字段,如果你想指定查询某些字段该怎么做呢?
指定查询字段-Select
//指定查询字段db.Select("name,age").Where(map[string]interface{}{"age":12,"sex":1}).Find(&u)
使用Struct和map作为查询条件
//使用Struct,相当于:select * from user where age =12 and sex=1db.Where(&User{Age:12,Sex:1}).Find(&u)//等同上一句db.Where(map[string]interface{}{"age":12,"sex":1}).Find(&u)
not 条件的使用
//where name not in ("xiaoming","xiaohong")db.Not("name","xiaoming","xiaohong").Find(&u)//同上db.Not("name",[]string{"xiaoming","xiaohong"}).Find(&u)
or 的使用
//where age > 12 or sex = 1db.Where("age > ?",12).Or("sex = ?",1).Find(&u)
order by 的使用
//order by age descdb.Where("age > ?",12).Or("sex = ?",1).Order("age desc").Find(&u)
limit 的使用
//limit 10db.Not("name",[]string{"xiaoming","xiaohong"}).Limit(10).Find(&u)
offset 的使用
//limit 300,10db.Not("name",[]string{"xiaoming","xiaohong"}).Limit(10).Offset(300).Find(&u)
count(*)
//count(*)var count intdb.Table("user").Where("age > ?",0).Count(&count)
注意:这里你在指定表名的情况下sql为:select count(*) from user where age > 0;
如上代码如果改为:
var count intvar user []Userdb.Where("age > ?",0).Find(&user).Count(&count)
相当于你先查出来[]User,然后统计这个list的长度。跟你预期的sql不相符。
group & having
rows, _ := db.Table("user").Select("count(*),sex").Group("sex"). Having("age > ?", 10).Rows()for rows.Next() { fmt.Print(rows.Columns())}
join
db.Table("user u").Select("u.name,u.age").Joins("left join user_ext ue on u.user_id = ue.user_id").Row()
如果有多个连接,用多个Join方法即可。
原生函数
db.Exec("DROP TABLE user;")db.Exec("UPDATE user SET name=? WHERE id IN (?)", "xiaoming", []int{11,22,33})db.Exec("select * from user where id > ?",10).Scan(&user)
一些函数
FirstOrInit 和 FirstOrCreate
获取第一个匹配的记录,若没有,则根据条件初始化一个新的记录:
//注意:where条件只能使用Struct或者map。如果这条记录不存在,那么会新增一条name=xiaoming的记录db.FirstOrInit(&u,User{Name:"xiaoming"})//同上db.FirstOrCreate(&u,User{Name:"xiaoming"})
Attrs
如果没有找到记录,则使用Attrs中的数据来初始化一条记录:
//使用attrs来初始化参数,如果未找到数据则使用attrs中的数据来初始化一条//注意:attrs 必须 要和FirstOrInit 或者 FirstOrCreate 连用db.Where(User{Name:"xiaoming"}).Attrs(User{Name:"xiaoming",Age:12}).FirstOrInit(&u)
Assign
//不管是否找的到,最终返回结构中都将带上Assign指定的参数db.Where("age > 12").Assign(User{Name:"xiaoming"}).FirstOrInit(&u)
Pluck
如果user表中你只想查询age这一列,该怎么返回呢,gorm提供了Pluck函数用于查询单列,返回数组:
var ages []intdb.Find(&u).Pluck("age",&ages)
Scan
Scan函数可以将结果转存储到另一个结构体中。
type SubUser struct{ Name string Age int}db.Table("user").Select("name,age").Scan(&SubUser)
sql.Row & sql.Rows
row和rows用户获取查询结果。
//查询一行row := db.Table("user").Where("name = ?", "xiaoming").Select("name, age").Row() // (*sql.Row)//获取一行的结果后,调用Scan方法来将返回结果赋值给对象或者结构体row.Scan(&name, &age)//查询多行rows, err := db.Model(&User{}).Where("sex = ?",1).Select("name, age, phone").Rows() // (*sql.Rows, error)defer rows.Close()for rows.Next() { ... rows.Scan(&name, &age, &email) ...}
日志#
Gorm有内置的日志记录器支持,默认情况下,它会打印发生的错误。
// 启用Logger,显示详细日志db.LogMode(true)// 禁用日志记录器,不显示任何日志db.LogMode(false)// 调试单个操作,显示此操作的详细日志db.Debug().Where("name = ?", "xiaoming").First(&User{})
参考文档:
go语言手册
Gorm 详细教程
Go orm框架gorm学习
Go ORM 概览
Go ORM 反向生成struct
实例
Shelnutt2/db2struct: Converts a mysql table into a golang struct (github.com)
Gorm 使用实例
没有无缘无故的荣耀
赞助我写出更好的博客
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~