golang类型安全的SQL构建器和结构体映射插件库sq的使用
Golang类型安全的SQL构建器和结构体映射插件库sq的使用
sq是一个代码生成的、类型安全的查询构建器和Go结构体映射库。
主要特点
-
避免魔法字符串:sq从数据库生成表结构体,确保您编写的查询始终反映数据库中的实际内容。
-
更好的NULL处理:sq将NULL扫描为零值,同时仍提供检查列是否为NULL的能力。
-
映射函数即SELECT子句:您只需编写查询,执行它,如果没有错误,数据就已经在您的Go变量中。
安装
go get github.com/bokwoon95/go-structured-query
根据您使用的数据库类型,还需要安装对应的代码生成器:
# Postgres
go get github.com/bokwoon95/go-structured-query/cmd/sqgen-postgres
# MySQL
go get github.com/bokwoon95/go-structured-query/cmd/sqgen-mysql
生成表结构
从数据库生成表结构:
# Postgres
sqgen-postgres tables --database 'postgres://name:pass@localhost:5432/dbname?sslmode=disable' --overwrite
# MySQL
sqgen-mysql tables --database 'name:pass@tcp(127.0.0.1:3306)/dbname' --schemas dbname --overwrite
导入sq
根据您使用的SQL方言导入对应的sq包:
// Postgres
import (
sq "github.com/bokwoon95/go-structured-query/postgres"
)
// MySQL
import (
sq "github.com/bokwoon95/go-structured-query/mysql"
)
示例代码
SELECT查询
-- SQL
SELECT u.user_id, u.name, u.email, u.created_at
FROM public.users AS u
WHERE u.name = 'Bob';
// Go
u := tables.USERS().As("u") // table is code generated
var user User
var users []User
err := sq.
From(u).
Where(u.NAME.EqString("Bob")).
Selectx(func(row *sq.Row) {
user.UserID = row.Int(u.USER_ID)
user.Name = row.String(u.NAME)
user.Email = row.String(u.EMAIL)
user.CreatedAt = row.Time(u.CREATED_AT)
}, func() {
users = append(users, user)
}).
Fetch(db)
if err != nil {
// handle error
}
INSERT操作
-- SQL
INSERT INTO public.users (name, email)
VALUES ('Bob', 'bob@email.com'), ('Alice', 'alice@email.com'), ('Eve', 'eve@email.com');
// Go
u := tables.USERS().As("u") // table is code generated
users := []User{
{Name: "Bob", Email: "bob@email.com"},
{Name: "Alice", Email: "alice@email.com"},
{Name: "Eve ", Email: "eve@email.com"},
}
rowsAffected, err := sq.
InsertInto(u).
Valuesx(func(col *sq.Column) {
for _, user := range users {
col.SetString(u.NAME, user.Name)
col.SetString(u.EMAIL, user.Email)
}
}).
Exec(db, sq.ErowsAffected)
if err != nil {
// handle error
}
UPDATE操作
-- SQL
UPDATE public.users
SET name = 'Bob', password = 'qwertyuiop'
WHERE email = 'bob@email.com';
// Go
u := tables.USERS().As("u") // table is code generated
user := User{
Name: "Bob",
Email: "bob@email.com",
Password: "qwertyuiop",
}
rowsAffected, err := sq.
Update(u).
Setx(func(col *sq.Column) {
col.SetString(u.NAME, user.Name)
col.SetString(u.PASSWORD, user.Password)
}).
Where(u.EMAIL.EqString(user.Email)).
Exec(db, sq.ErowsAffected)
if err != nil {
// handle error
}
DELETE操作
-- SQL
DELETE FROM public.users AS u
USING public.user_roles AS ur
JOIN public.user_roles_students AS urs ON urs.user_role_id = ur.user_role_id
WHERE u.user_id = ur.user_id AND urs.team_id = 15;
// Go
u := tables.USERS().As("u") // tables are code generated
ur := tables.USER_ROLES().As("ur") // tables are code generated
urs := tables.USER_ROLES_STUDENTS().As("urs") // tables are code generated
rowsAffected, err := sq.
DeleteFrom(u).
Using(ur).
Join(urs, urs.USER_ROLE_ID.Eq(ur.USER_ROLE_ID)).
Where(
u.USER_ID.Eq(ur.USER_ID),
urs.TEAM_ID.EqInt(15),
).
Exec(db, sq.ErowsAffected)
if err != nil {
// handle error
}
项目状态
外部API被认为是稳定的。任何更改只会添加到API中(如支持自定义记录器和结构化日志记录)。
更多关于golang类型安全的SQL构建器和结构体映射插件库sq的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang类型安全的SQL构建器和结构体映射插件库sq的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 类型安全的 SQL 构建器和结构体映射:sq 库使用指南
sq 是一个 Go 语言的类型安全 SQL 构建器和结构体映射库,它提供了编译时类型检查的 SQL 查询构建能力,同时支持将查询结果自动映射到结构体。
安装 sq
go get github.com/bokwoon95/sq
基本用法
1. 构建 SQL 查询
import (
"github.com/bokwoon95/sq"
"github.com/bokwoon95/sq/sqlite"
)
type User struct {
ID int
Name string
Email string
}
func main() {
// 创建查询构建器
query := sqlite.From("users").
Select("id", "name", "email").
Where("age > ?", 18).
OrderBy("name ASC")
// 获取生成的 SQL 和参数
sql, args, err := sq.ToSQL(query)
if err != nil {
panic(err)
}
fmt.Println("SQL:", sql)
fmt.Println("Args:", args)
}
2. 结构体映射
sq 支持将查询结果自动映射到结构体:
func getUsers(db *sql.DB) ([]User, error) {
var users []User
// 构建查询
query := sqlite.From("users").
Select("id", "name", "email").
Where("active = ?", true)
// 执行查询并映射结果
err := sq.FetchAll(db, query, &users)
if err != nil {
return nil, err
}
return users, nil
}
3. 类型安全的查询构建
sq 支持类型安全的查询构建,可以避免字段名拼写错误:
// 定义表结构
type USER struct {
sq.TableStruct
ID sq.NumberField
Name sq.StringField
Email sq.StringField
Age sq.NumberField
}
func getAdultUsers(db *sql.DB) ([]User, error) {
u := USER{TableStruct: sq.TableStruct{TableName: "users"}}
var users []User
query := sqlite.From(u).
Select(u.ID, u.Name, u.Email).
Where(u.Age.Gt(18)).
OrderBy(u.Name)
err := sq.FetchAll(db, query, &users)
if err != nil {
return nil, err
}
return users, nil
}
高级功能
1. 复杂查询
func getUsersWithPosts(db *sql.DB) ([]struct {
User User
Posts []Post
}, error) {
u := USER{TableStruct: sq.TableStruct{TableName: "users"}}
p := POST{TableStruct: sq.TableStruct{TableName: "posts"}}
var result []struct {
User User
Posts []Post
}
query := sqlite.From(u).
LeftJoin(p, p.UserID.Eq(u.ID)).
Select(
u.ID, u.Name, u.Email,
p.ID, p.Title, p.Content,
).
Where(u.Active.IsTrue())
err := sq.FetchAll(db, query, &result)
if err != nil {
return nil, err
}
return result, nil
}
2. 事务支持
func createUserWithTransaction(db *sql.DB, user User) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
u := USER{TableStruct: sq.TableStruct{TableName: "users"}}
// 插入用户
_, err = sq.Exec(tx, sqlite.InsertInto(u).
Columns(u.Name, u.Email).
Values(user.Name, user.Email))
if err != nil {
return err
}
return tx.Commit()
}
3. 条件构建
func searchUsers(db *sql.DB, nameFilter string, minAge int) ([]User, error) {
u := USER{TableStruct: sq.TableStruct{TableName: "users"}}
var users []User
query := sqlite.From(u).
Select(u.ID, u.Name, u.Email).
Where(u.Age.Gte(minAge))
if nameFilter != "" {
query = query.Where(u.Name.Like("%" + nameFilter + "%"))
}
err := sq.FetchAll(db, query, &users)
if err != nil {
return nil, err
}
return users, nil
}
优势
- 类型安全:编译时检查 SQL 字段和类型
- 自动映射:查询结果自动映射到结构体
- SQL 注入防护:自动参数化查询
- 多数据库支持:支持 SQLite, PostgreSQL, MySQL 等
- 链式调用:流畅的 API 设计
sq 库通过类型安全的方式构建 SQL 查询,大大减少了运行时错误的风险,同时保持了代码的简洁性和可读性。