Exec 原生 SQL
db.Exec( " DROP TABLE users " )
db.Exec( " UPDATE orders SET shipped_at=? WHERE id IN ? " , time.Now(), []int64{ 1 , 2 , 3 })
// Exec SQL 表达式
db.Exec( " update users set money=? where name = ? " , gorm.Expr( " money * ? + ? " , 10000 , 1 ), " jinzhu " )
注意 GORM 允许缓存预编译 SQL 语句来提高性能,查看 性能 获取详情
命名参数
GORM 支持 sql.NamedArg 、 map[string]interface{}{} 或 struct 形式的命名参数,例如:
db.Where( " name1 = @name OR name2 = @name " , sql.Named( " name " , " jinzhu " )).Find(& user)
// SELECT * FROM `users` WHERE name1 = "jinzhu" OR name2 = "jinzhu"
db.Where( " name1 = @name OR name2 = @name " , map[ string ] interface {}{ " name " : " jinzhu2 " }).First(& result3)
// SELECT * FROM `users` WHERE name1 = "jinzhu2" OR name2 = "jinzhu2" ORDER BY `users`.`id` LIMIT 1
// 原生 SQL 及命名参数
db.Raw( " SELECT * FROM users WHERE name1 = @name OR name2 = @name2 OR name3 = @name " ,
sql.Named( " name " , " jinzhu1 " ), sql.Named( " name2 " , " jinzhu2 " )).Find(& user)
// SELECT * FROM users WHERE name1 = "jinzhu1" OR name2 = "jinzhu2" OR name3 = "jinzhu1"
db.Exec( " UPDATE users SET name1 = @name, name2 = @name2, name3 = @name " ,
sql.Named( " name " , " jinzhunew " ), sql.Named( " name2 " , " jinzhunew2 " ))
// UPDATE users SET name1 = "jinzhunew", name2 = "jinzhunew2", name3 = "jinzhunew"
db.Raw( " SELECT * FROM users WHERE (name1 = @name AND name3 = @name) AND name2 = @name2 " ,
map[ string ] interface {}{ " name " : " jinzhu " , " name2 " : " jinzhu2 " }).Find(& user)
// SELECT * FROM users WHERE (name1 = "jinzhu" AND name3 = "jinzhu") AND name2 = "jinzhu2"
type NamedArgument struct {
Name string
Name2 string
}
db.Raw( " SELECT * FROM users WHERE (name1 = @Name AND name3 = @Name) AND name2 = @Name2 " ,
NamedArgument{Name: " jinzhu " , Name2: " jinzhu2 " }).Find(& user)
// SELECT * FROM users WHERE (name1 = "jinzhu" AND name3 = "jinzhu") AND name2 = "jinzhu2"
DryRun 模式
在不执行的情况下生成 SQL ,可以用于准备或测试生成的 SQL,详情请参考 Session
stmt := db.Session(&Session{DryRun: true }).First(&user, 1 ).Statement
stmt.SQL.String() // => SELECT * FROM `users` WHERE `id` = $1 ORDER BY `id`
stmt.Vars // => []interface{}{1}
Row & Rows
获取 *sql.Row 结果
// 使用 GORM API 构建 SQL row := db.Table( " users " ).Where( " name = ? " , " jinzhu " ).Select( " name " , " age " ).Row() row.Scan( &name, & age) // 使用原生 SQL row := db.Raw( " select name, age, email from users where name = ? " , " jinzhu " ).Row() row.Scan( &name, &age, &email)
获取 *sql.Rows 结果
// 使用 GORM API 构建 SQL
rows, err := db.Model(&User{}).Where( " name = ? " , " jinzhu " ).Select( " name, age, email " ).Rows()
defer rows.Close()
for rows.Next() {
rows.Scan( &name, &age, & email)
// 业务逻辑...
}
// 原生 SQL
rows, err := db.Raw( " select name, age, email from users where name = ? " , " jinzhu " ).Rows()
defer rows.Close()
for rows.Next() {
rows.Scan( &name, &age, & email)
// 业务逻辑...
}
转到 FindInBatches 获取如何在批量中查询和处理记录的信息, 转到 Group 条件 获取如何构建复杂 SQL 查询的信息
将 sql.Rows 扫描至 model
使用 ScanRows 将一行记录扫描至 struct,例如:
rows, err := db.Model(&User{}).Where( " name = ? " , " jinzhu " ).Select( " name, age, email " ).Rows() // (*sql.Rows, error)
defer rows.Close()
var user User
for rows.Next() {
// ScanRows 将一行扫描至 user
db.ScanRows(rows, & user)
// 业务逻辑...
}
高级
子句(Clause)
GORM 内部使用 SQL builder 生成 SQL。对于每个操作,GORM 都会创建一个 *gorm.Statement 对象,所有的 GORM API 都是在为 statement 添加/修改 Clause ,最后,GORM 会根据这些 Clause 生成 SQL
例如,当通过 First 进行查询时,它会在 Statement 中添加以下 Clause
clause.Select{Columns: " * " }
clause.From{Tables: clause.CurrentTable}
clause.Limit{Limit: 1 }
clause.OrderByColumn{
Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
}
然后 GORM 在 Query callback 中构建最终的查询 SQL,像这样:
Statement.Build( " SELECT " , " FROM " , " WHERE " , " GROUP BY " , " ORDER BY " , " LIMIT " , " FOR " )
生成 SQL:
SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
您可以自定义 Clause 并与 GORM 一起使用,这需要实现 Interface 接口
可以参考 示例
子句构造器
不同的数据库, Clause 可能会生成不同的 SQL,例如:
db.Offset( 10 ).Limit( 5 ).Find(& users) // SQL Server 会生成 // SELECT * FROM "users" OFFSET 10 ROW FETCH NEXT 5 ROWS ONLY // MySQL 会生成 // SELECT * FROM `users` LIMIT 5 OFFSET 10
子句选项 之所以支持 Clause,是因为 GORM 允许数据库驱动程序通过注册 Clause Builder 来取代默认值,这儿有一个 Limit 的示例
GORM 定义了很多 Clause,其中一些 Clause 提供了你可能会用到的选项
尽管很少会用到它们,但如果你发现 GORM API 与你的预期不符合。这可能可以很好地检查它们,例如
db.Clauses(clause.Insert{Modifier: " IGNORE " }).Create(& user)
// INSERT IGNORE INTO users (name,age...) VALUES ("jinzhu",18...);
GORM 提供了 StatementModifier 接口,允许您修改语句,使其符合您的要求,这儿有一个 Hint 示例 StatementModifier
import " gorm.io/hints "
db.Clauses(hints.New( " hint " )).Find(& User{})
// SELECT * /*+ hint */ FROM `users`
GO语言GORM的SQL构建器
标签:命名参数 修改 对象 HERE article OLE 注册 current tab