建立数据库连接
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
var db *gorm.DB
func OpenDB() {
dsn := "root:adss123@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True&loc=Local"
res, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
db = res
if err != nil {
log.Fatal(err)
}
fmt.Printf("成功:%v\n", db)
}
建立模型
type TestTb2 struct {
Username string
Password string
TestTb2User1ID uint
gorm.Model
}
raw原生语句
type Result struct {
ID int
Name string
Age int
}
var result Result
db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)
db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)
var age int
db.Raw("SELECT SUM(age) FROM users WHERE role = ?", "admin").Scan(&age)
var users []User
db.Raw("UPDATE users SET name = ? WHERE age = ? RETURNING id, name", "jinzhu", 20).Scan(&users)
实验案例实现两个查询与修改功能
查询
func RawSelect(Any any) {
OpenDB()
tx := db.Raw("select * from test_tb2 where id=?", 9).Scan(Any)
if tx.Error != nil {
fmt.Printf("查询失败,err:%v\n", tx.Error)
} else {
fmt.Printf("查询成功,结果为%v\n", Any)
}
}
修改
func RawUpdate(Any any) {
OpenDB()
tx := db.Raw("update test_tb2 set username=? where id=? ", "niuerpao", 9).Scan(Any)
if tx.Error != nil {
fmt.Printf("查询失败,err:%v\n", tx.Error)
} else {
fmt.Printf("查询成功,结果为%v\n", Any)
}
}
暂时发现我的mysql不支持returning语句,问题暂时保存。
exec原生语句
db.Exec("DROP TABLE users")
db.Exec("UPDATE orders SET shipped_at = ? WHERE id IN ?", time.Now(), []int64{1, 2, 3})
// Exec with SQL Expression
db.Exec("UPDATE users SET money = ? WHERE name = ?", gorm.Expr("money * ? + ?", 10000, 1), "jinzhu")
实验案例如下
func ExecUpdate(Any any) {
OpenDB()
tx := db.Exec("update test_tb2 set username=? where id=?", gorm.Expr("concat(username,?)", "_houzhui"), 9)
if tx.Error != nil {
fmt.Printf("查询失败,err:%v\n", tx.Error)
} else {
RawSelect(Any)
fmt.Printf("修改成功,结果为%v\n", Any)
}
}
小笔记:sql语句中字符串后增加字符串使用concat()语句,并不是常规的+。
GORM 支持 sql.NamedArg、map[string]interface{}{} 或 struct 形式的命名参数,例如:
在where语句中,过多的?在后期修改上会很繁琐,多使用命名参数,也许可以简化以后代码的修改难度。
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"
实验案例如下
在Raw语句中利用map进行参数命名
func RawSelect(Any any) {
OpenDB()
tx := db.Raw("select * from test_tb2 where username=@name and password=@password", map[string]interface{}{"name": "ylj", "password": "123"}).Scan(Any)
if tx.Error != nil {
fmt.Printf("查询失败,err:%v\n", tx.Error)
} else {
fmt.Printf("查询成功,结果为%v\n", Any)
}
}
row,rows是sql包里的方法。
其中row包含方法Err(),Scan(),包含属性err,rows
rows中包含方法很多,常见的是Next(),Close()等
获取 *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)
// 业务逻辑...
}
实验案例如下
row
func RawGetRow(Any any) {
OpenDB()
res := ""
row := db.Raw("select username from test_tb2 where id=?", 9).Row()
err := row.Scan(&res)
if err != nil {
fmt.Printf("查询失败,err:%v\n", err)
} else {
fmt.Printf("查询成功,结果为%v\n", res)
}
}
发现Row()下的Scan方法无法直接将结果扫描进结构体内,只能将每个字段信息单独提取出来。可能会有解决办法,暂时没发现如何调用Row()下的Scan方法进行结构体扫描。本人暂时选择直接调用DB下的Scan方法,DB下的Scan可以直接扫描结构体。
rows
rows可以使用 ScanRows 将一行记录扫描至 struct,例如:
func RawGetRows(Any any) {
OpenDB()
rows, err := db.Raw("select * from test_tb2 where username = ?", "1").Rows()
if err != nil {
fmt.Printf("查询失败,err:%v\n", err)
} else {
defer rows.Close()
for rows.Next() {
db.ScanRows(rows, Any)
fmt.Printf("查询成功:%v\n", Any)
}
}
}
在使用rows时要记得Close(),因为rows会维护这个数据库连接,当 tx 想再次调用当前连接进行数据库操作的时候,因为连接还没有断开,没有调用 rows.Close(),tx 无法再从连接池里获取当前连接。