golang高效构建SQL查询语句插件库Squirrel的使用
Golang高效构建SQL查询语句插件库Squirrel的使用
简介
Squirrel是一个Go语言的流式SQL生成器,它可以帮助你从可组合的部分构建SQL查询。Squirrel不是一个ORM。
基本用法
安装
import "github.com/Masterminds/squirrel"
查询示例
import sq "github.com/Masterminds/squirrel"
// 基础查询
users := sq.Select("*").From("users").Join("emails USING (email_id)")
// 添加条件
active := users.Where(sq.Eq{"deleted_at": nil})
// 生成SQL
sql, args, err := active.ToSql()
// sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
插入示例
sql, args, err := sq.
Insert("users").Columns("name", "age").
Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
ToSql()
// sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
执行查询
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
three_stooges := stooges.Limit(3)
rows, err := three_stooges.RunWith(db).Query()
// 等同于:
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3",
"moe", "larry", "curly", "shemp")
条件查询构建
if len(q) > 0 {
users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
}
高级特性
语句缓存和构建器
// StmtCache缓存准备好的语句
dbCache := sq.NewStmtCache(db)
// StatementBuilder保持语法整洁
mydb := sq.StatementBuilder.RunWith(dbCache)
select_users := mydb.Select("*").From("users")
PostgreSQL支持
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
// 使用问号作为占位符...
sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna").ToSql()
// ...squirrel会根据PlaceholderFormat替换它们
// sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
// 可以检索id...
query := sq.Insert("nodes").
Columns("uuid", "type", "data").
Values(node.Uuid, node.Type, node.Data).
Suffix("RETURNING \"id\"").
RunWith(m.db).
PlaceholderFormat(sq.Dollar)
query.QueryRow().Scan(&node.id)
转义问号
可以通过插入两个问号来转义问号:
SELECT * FROM nodes WHERE meta->'format' ??| array[?,?]
使用Dollar占位符时会生成:
SELECT * FROM nodes WHERE meta->'format' ?| array[$1,$2]
完整示例Demo
package main
import (
"database/sql"
"fmt"
"log"
sq "github.com/Masterminds/squirrel"
_ "github.com/lib/pq"
)
func main() {
// 连接数据库
db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 创建StatementBuilder
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
// 1. 查询示例
query := psql.Select("id", "name", "email").
From("users").
Where(sq.Eq{"active": true}).
Limit(10)
sql, args, err := query.ToSql()
if err != nil {
log.Fatal(err)
}
fmt.Println("生成的SQL:", sql)
fmt.Println("参数:", args)
// 执行查询
rows, err := query.RunWith(db).Query()
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 处理结果...
// 2. 插入示例
insert := psql.Insert("users").
Columns("name", "age").
Values("John", 30).
Values("Alice", sq.Expr("? + 5", 25))
sql, args, err = insert.ToSql()
if err != nil {
log.Fatal(err)
}
fmt.Println("\n生成的插入SQL:", sql)
fmt.Println("参数:", args)
// 执行插入
_, err = insert.RunWith(db).Exec()
if err != nil {
log.Fatal(err)
}
// 3. 更新示例
update := psql.Update("users").
Set("name", "Bob").
Set("age", sq.Expr("age + 1")).
Where(sq.Eq{"id": 1})
sql, args, err = update.ToSql()
if err != nil {
log.Fatal(err)
}
fmt.Println("\n生成的更新SQL:", sql)
fmt.Println("参数:", args)
// 4. 条件查询构建
searchTerm := "john"
query = psql.Select("*").From("users")
if searchTerm != "" {
query = query.Where("name LIKE ?", fmt.Sprintf("%%%s%%", searchTerm))
}
sql, args, err = query.ToSql()
if err != nil {
log.Fatal(err)
}
fmt.Println("\n条件查询SQL:", sql)
fmt.Println("参数:", args)
}
常见问题
-
如何构建复合键/元组的IN查询?
使用
Or
和Eq
组合:sq.Or{ sq.Eq{"col1": 1, "col2": 2}, sq.Eq{"col1": 3, "col2": 4}}
生成的SQL:
WHERE (col1 = 1 AND col2 = 2) OR (col1 = 3 AND col2 = 4)
-
为什么
Eq{"mynumber": []uint8{1,2,3}}
不会转换为IN查询?因为
[]byte
在Go中只是[]uint8
的别名,无法区分两者。 -
某些功能文档不完善?
测试用例可以作为文档的一部分参考。
许可证
Squirrel采用MIT许可证发布。
更多关于golang高效构建SQL查询语句插件库Squirrel的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高效构建SQL查询语句插件库Squirrel的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Squirrel: Golang高效构建SQL查询语句插件库
Squirrel是一个Go语言的SQL查询构建器库,它可以帮助开发者以更优雅、更安全的方式构建SQL查询语句,避免SQL注入风险,同时提高代码可读性。
基本特性
- 链式调用:提供流畅的API接口
- 类型安全:减少SQL注入风险
- 多数据库支持:支持MySQL、PostgreSQL、SQLite等
- 可扩展性:可以自定义SQL方言
安装
go get github.com/Masterminds/squirrel
基本使用示例
1. 简单查询
import sq "github.com/Masterminds/squirrel"
// 构建SELECT查询
query, args, err := sq.Select("id", "name", "email").
From("users").
Where(sq.Eq{"active": true}).
OrderBy("name ASC").
Limit(10).
ToSql()
// 输出: SELECT id, name, email FROM users WHERE active = ? ORDER BY name ASC LIMIT 10
// args: [true]
2. 条件查询
// 复杂条件查询
query, args, err := sq.Select("*").
From("orders").
Where(sq.And{
sq.Eq{"status": "completed"},
sq.Or{
sq.Gt{"amount": 1000},
sq.Lt{"created_at": "2023-01-01"},
},
}).
ToSql()
// 输出: SELECT * FROM orders WHERE (status = ?) AND ((amount > ?) OR (created_at < ?))
// args: ["completed", 1000, "2023-01-01"]
3. 插入数据
query, args, err := sq.Insert("users").
Columns("name", "email", "created_at").
Values("John Doe", "john@example.com", time.Now()).
ToSql()
// 输出: INSERT INTO users (name,email,created_at) VALUES (?,?,?)
// args: ["John Doe", "john@example.com", "2023-11-15 12:00:00"]
4. 更新数据
query, args, err := sq.Update("users").
Set("name", "Jane Doe").
Set("email", "jane@example.com").
Where(sq.Eq{"id": 1}).
ToSql()
// 输出: UPDATE users SET name = ?, email = ? WHERE id = ?
// args: ["Jane Doe", "jane@example.com", 1]
5. 删除数据
query, args, err := sq.Delete("users").
Where(sq.Eq{"id": 1}).
ToSql()
// 输出: DELETE FROM users WHERE id = ?
// args: [1]
高级特性
1. 子查询
subQuery := sq.Select("user_id").From("orders").Where(sq.Gt{"amount": 1000})
query, args, err := sq.Select("*").
From("users").
Where(sq.Eq{"id": subQuery}).
ToSql()
// 输出: SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > ?)
// args: [1000]
2. JOIN操作
query, args, err := sq.Select("u.name", "o.amount").
From("users u").
Join("orders o ON u.id = o.user_id").
Where(sq.Gt{"o.amount": 500}).
ToSql()
// 输出: SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE o.amount > ?
// args: [500]
3. 批量插入
query, args, err := sq.Insert("users").
Columns("name", "email").
Values("User1", "user1@example.com").
Values("User2", "user2@example.com").
Values("User3", "user3@example.com").
ToSql()
// 输出: INSERT INTO users (name,email) VALUES (?,?),(?,?),(?,?)
// args: ["User1", "user1@example.com", "User2", "user2@example.com", "User3", "user3@example.com"]
4. 占位符方言支持
// 使用PostgreSQL的$n占位符
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
query, args, err := psql.Select("*").From("users").Where(sq.Eq{"id": 1}).ToSql()
// 输出: SELECT * FROM users WHERE id = $1
// args: [1]
实际应用示例
func GetActiveUsers(db *sql.DB, minOrders int) ([]User, error) {
query, args, err := sq.Select("u.id", "u.name", "u.email", "COUNT(o.id) as order_count").
From("users u").
LeftJoin("orders o ON u.id = o.user_id").
Where(sq.Eq{"u.active": true}).
GroupBy("u.id").
Having("COUNT(o.id) >= ?", minOrders).
OrderBy("order_count DESC").
ToSql()
if err != nil {
return nil, err
}
rows, err := db.Query(query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
var users []User
for rows.Next() {
var u User
if err := rows.Scan(&u.ID, &u.Name, &u.Email, &u.OrderCount); err != nil {
return nil, err
}
users = append(users, u)
}
return users, nil
}
优势总结
- 安全性:自动处理参数化查询,防止SQL注入
- 可读性:链式调用使代码更易读和维护
- 灵活性:支持复杂查询构建
- 多数据库支持:通过占位符格式支持不同数据库
Squirrel是构建SQL查询的强大工具,特别适合需要动态构建查询的应用场景。它既保持了SQL的灵活性,又提供了Go语言的类型安全和结构化的构建方式。