GO orm 框架GORM学习

网友投稿 1302 2022-10-11

GO orm 框架GORM学习

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 字段标签

标签名

说明

​column​

指定 db 列名

​type​

列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:​​not null​​​、​​size​​​, ​​autoIncrement​​​… 像 ​​varbinary(8)​​​ 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:​​MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT​

​size​

指定列大小,例如:​​size:256​

​primaryKey​

指定列为主键

​unique​

指定列为唯一

​default​

指定列的默认值

​not null​

指定列为 NOT NULL

​autoIncrement​

指定列为自动增长

​comment​

迁移时为字段添加注释

​index​

根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情

更多约定,请查看官方文档

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 1 0xc0001a21c0 0}id: 1插入记录错误: 插入记录的条数: 1--- PASS: TestAddOne (0.04s)PASS*/

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插入记录错误: 插入记录的条数: 3插入ID: 4插入ID: 5插入ID: 6--- PASS: TestBatchInsert (0.02s)PASS*/

更新插入方式,参见文档: ​​查询

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查询错误: --- PASS: TestGetByFind (0.00s)PASS*/

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: Res2: 4 err: Res3: 1 err: --- PASS: TestGetByStringWhere (0.02s)PASS*/

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: map条件: 3 err: 主键切片: 4 err: --- PASS: TestGetByStructAndMapWhere (0.01s)PASS*/

@注意 当使用结构作为条件查询时,​​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: 结构体条件更新: 1 err: --- PASS: TestUpdateColumn (0.06s)PASS*/

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小时内删除侵权内容。

上一篇:SpringBoot、mybatis返回树结构的数据实现
下一篇:[Mitoo-weapp]是一款基于小程序的ui组件库
相关文章

 发表评论

暂时没有评论,来抢沙发吧~