golang学习笔记(9)-gorm原生sql

gorm使用原生sql功能

目录

  • gorm使用原生sql功能
    • 准备工作
    • 原生查询 SQL 和 Scan
    • 命名参数
    • Row & Rows

准备工作

建立数据库连接

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
}

数据表预存数据
golang学习笔记(9)-gorm原生sql_第1张图片

原生查询 SQL 和 Scan

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

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 无法再从连接池里获取当前连接。

你可能感兴趣的:(sql,golang,学习)