GORM 最佳实践(4) | 青训营笔记
- 数据序列化与 SQL 表达式 √
- 批量数据操作 √
- 代码复用、分库分表、Sharding √
- 混沌工程/压测 √
- Logger/Trace √
- Migrator
- Gen 代码生成/Raw SQL
- 安全
Migrator - 数据库迁移管理
db.AutoMigrate(&User{})
import "github.com/go-gormigate/gormigate/v2"
m := gormigate.New(db, gormigate.DefaultOptions, []*gormigate.Migration{
{
ID: "201608301400",
Migrate: func(tx *gorm.DB) error {
type User struct {
Name string
}
return tx.Model(&User{}).AddColumn(&User{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Model(&User{}).DropColumn(&User{})
},
},
})
m.Migrate()
Gen 代码生成/Raw SQL - Raw SQL
db.Raw("SELECT id, name, age FROM users WHERE name = ?", "jinzhu").Scan(&result)
db.Raw("SELECT id, name, age FROM users WHERE name = @name","jinzhu").Scan(&result)
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN ?", time.Now(),[]int64{1,2,3})
row := db.Table("users").Where("name = ?", "jinzhu").Select("name", "age").Row()
row.Scan(&name, &age)
DB.Where("name1 = @name OR name2 = @name2", sql.Named("name","jinzhu")).Find(&user)
DB.Where("name1 = @name OR name2 = @name2", map[string]interface{}{"name": "jinzhu"}).Find(&user)
DB.Where("name1 = @name OR name2 = @name2", User{Name: "jinzhu"}).Find(&user)
DB.Raw(
"SELECT * FROM users WHERE name1 = @name OR name2 = @name2 OR name3 = @name",
sql.Named("name", "jinzhu"),sql.Named("name2","jinzhu2")
).Find(&user)
- 第一行代码使用了
db.Raw来构造原生的SQL语句,并通过Scan方法将查询结果映射到result变量中。 - 第二行代码与第一行代码类似,但是使用了
@符号来标识参数,同时也通过Scan方法将查询结果映射到result变量中。 - 第三行代码使用了
db.Exec来执行原生的SQL语句,其中第一个参数是要执行的SQL语句,第二个参数是要传递给SQL语句的参数,执行结果不返回值。 - 第四行代码用于查询某个表的行数据并映射到单个变量中,其中
Table方法指定要查询的表,Where方法指定查询条件,Select方法指定返回的列,而Row和Scan方法用于将查询结果映射到变量中。 - 第五行代码使用了
sql.Named和map[string]interface{}两种方式来传递参数,其中Named方式是通过sql.Named类型来指定参数名和值,而map方式是通过键值对来指定参数名和值。与之类似的是第六行代码,但是使用了结构体的方式。 - 第七行代码与第一、二行代码类似,但是查询的
SQL语句使用了多个参数。
Gen 代码生成/Raw SQL - Gen
type Query interface {
FindUser(id int32, name string, age int)(gen.T, err)
}
g := gen.NewGenerator(gen.Config{
OutPath: "../dal/query",
})
g.ApplyBasic(model.User{})
g.ApplyInterface(func(query method.Query) {}, model.User{})
g.Execute()
user, err := query.User.FindUser(10, "jinzhu", 16)
定义了 Query 接口,接口里只有一个方法 FindUser,该方法接受三个参数:id,name 和 age,返回两个值:gen.T 类型和 err 类型。
新建一个 Generator 对象,指定其输出路径为 "../dal/query"。
调用 Generator 对象的 ApplyBasic 方法,传入 model.User{},这意味着我们要使用该对象的基本方法。
调用 Generator 对象的 ApplyInterface 方法,传入一个匿名函数。该匿名函数接收一个 method.Query 类型的参数,该参数是一个结构体,表示一个基本的查询方法。这个函数在执行时会根据 model.User{} 的字段生成相应的查询方法。
调用 Generator 对象的 Execute 方法,根据前面的设置生成代码文件到指定的输出路径。
最后执行查询代码,调用上述生成的查询方法,查询 id 为 10、name 为 "jinzhu"、age 为 16 的用户信息,并将查询结果赋值给 user 变量,如果有错误,则将 err 赋值给 err 变量。
安全问题
db.Cretae(User{Name: userInput})
db.Model(user).Update("name",userInput)
db.Where(User{Name: userInput}).First(&user)
db.Where("name = ?", userInput).First(&user)
sql := fmt.Sprintf("name = %v",userInput)
db.Where(sql).First(&user)
db.Select("name; drop table users;").First(&user)
db.Distinct("name; drop table users;").First(&user)
db.Model(&user).Pluck("name; drop table users;", &names)
db.Group("name; drop table users;").First(&user)
db.Group("name").Having("1 = 1; drop table users;").First(&user)
db.Raw("select name from users; drop table users;").First(&user)
db.Exec("select name from users; drop table users;")
db是一个数据库连接对象,User是一个结构体,包含了名为Name的属性。
db.Create:创建一个新的User对象,将其Name属性设置为输入的userInput值;db.Model.Update:在db连接的User表中,找到Name属性为user.Name的记录,将其Name属性更新为输入的userInput值;db.Where.First:在db连接的User表中,查找满足Name属性为输入的userInput值的记录,并将其中的第一条记录赋值给user对象;db.Select.First:在db连接的User表中,查询所有记录的Name属性,并将其中的第一条记录赋值给user对象;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险;db.Distinct.First:与上一个用法相同,只是使用了Distinct关键字去重;db.Model.Pluck:在db连接的User表中,查询所有记录的Name属性,并将结果存储到names变量中;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险;db.Group.First:在db连接的User表中,按照Name属性进行分组,再找到第一条记录,赋值给user对象;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险;db.Group.Having.First:在db连接的User表中,按照Name属性进行分组,再查找满足1=1条件的记录,并将其中的第一条记录赋值给user对象;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险;db.Raw.First:在db连接的User表中使用原生SQL语句进行查询,并将其中的第一条记录赋值给user对象;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险;db.Exec:在db连接的User表中使用原生SQL语句进行查询,并将结果返回给调用者;其中,查询语句中包含了一个恶意的SQL注入代码,可能会造成数据库被破坏的风险。