用官方提供的ORM用的不习惯,就花时间搞了个链式的操作,主要是方便PHP转GO的小白子,可
以灵活运用,我也搞了Redis的快捷函数操作,和sql表名数据同步
conf/app.conf 配置信息
Go
# MySQL服务器地址
db_host = 127.0.0.1
# MySQL端口
db_port = 3306
# MySQL用户名
db_user = root
# MySQL密码
db_password = root
# MySQL数据库表名
db_name = golang
services/database.go
直接在main.go 初始化数据库,services.InitDatabase()
Go
/*
+--------------------------------------------------------------------------------
| If this code works, it was written by Xven. If not, I don't know who wrote it.
+--------------------------------------------------------------------------------
| Statement: An Ordinary Person
+--------------------------------------------------------------------------------
| Author: Xven <QQ:270988107>
+--------------------------------------------------------------------------------
| Copyright (c) 2025 Xven All rights reserved.
+--------------------------------------------------------------------------------
*/
package services
import (
"context"
"fmt"
"time"
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/core/config"
_ "github.com/go-sql-driver/mysql"
)
// DB 是全局数据库连接实例
var DB orm.Ormer // 修改为使用beego的orm
func InitDatabase() error {
// 读取配置
host, _ := config.String("db_host")
port, _ := config.String("db_port")
user, _ := config.String("db_user")
password, _ := config.String("db_password")
dbName, _ := config.String("db_name")
// 注册MySQL驱动
orm.RegisterDriver("mysql", orm.DRMySQL)
// 构建DSN
dsn := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + dbName + "?charset=utf8&parseTime=true"
// 注册数据库时设置合理的连接池参数
maxIdle := 20
maxOpen := 80
// 注册默认数据库
if err := orm.RegisterDataBase("default", "mysql", dsn, maxIdle, maxOpen); err != nil {
if err.Error() == "DataBase alias name `default` already registered, cannot reuse" {
// 如果已经注册,返回一个自定义错误
return fmt.Errorf("数据库已注册: %w", err)
}
return fmt.Errorf("MySQL连接失败: %w", err)
}
// 获取数据库连接
db, err := orm.GetDB("default")
if err != nil {
return fmt.Errorf("获取数据库连接失败: %w", err)
}
// 修改连接生命周期为7小时50分钟(比MySQL的8小时短)
db.SetConnMaxLifetime(28200 * time.Second) // 28200s = 7h50m
// 空闲连接超时设为30分钟(小于服务端可能的interactive_timeout)
db.SetConnMaxIdleTime(30 * time.Minute) // 1800s = 30m
return nil
}
builder/db.go
Go
/*
+--------------------------------------------------------------------------------
| If this code works, it was written by Xven. If not, I don't know who wrote it.
+--------------------------------------------------------------------------------
| Statement: An Ordinary Person
+--------------------------------------------------------------------------------
| Author: Xven <QQ:270988107>
+--------------------------------------------------------------------------------
| Copyright (c) 2025 Xven All rights reserved.
+--------------------------------------------------------------------------------
*/
package builder
import (
"fmt"
"strings"
"github.com/astaxie/beego/orm"
)
// JoinType 定义连接类型常量
const (
JoinInner = "INNER"
JoinLeft = "LEFT"
JoinRight = "RIGHT"
)
// JoinInfo 存储JOIN信息
type JoinInfo struct {
Type string // 连接类型:INNER/LEFT/RIGHT
Table string // 连接表名
Condition string // 连接条件
}
type DB struct {
ormer orm.Ormer
tableName string
qs orm.QuerySeter
fields []string // SELECT字段
joins []JoinInfo // JOIN信息
whereConditions []string // WHERE条件语句
whereParams []interface{} // WHERE参数
orderBy string // 排序语句
limit int // 限制条数
offset int // 偏移量
rawMode bool // 标记是否使用原生SQL模式
}
/**
* 初始化DB实例
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
*/
func NewDB() *DB {
o := orm.NewOrm()
return &DB{
ormer: o,
qs: nil, // 不再使用空表名
}
}
/**
* Table 设置表名
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users")
*/
func (d *DB) Table(tableName string) *DB {
d.tableName = tableName
d.qs = d.ormer.QueryTable(tableName)
return d
}
/**
* Join 添加关联查询
* @Author Xven <[email protected]>
* @param joinType 连接类型(INNER/LEFT/RIGHT)
* @param table 连接表名(可包含别名)
* @param condition 连接条件(包含占位符时需自行处理参数)
* @return *DB 返回链式调用对象
*
* 示例1:内连接基础用法
* db.Table("users").Join(JoinInner, "profiles", "profiles.user_id = users.id")
*
* 示例2:带别名连接
* db.Table("u").Join(JoinLeft, "profiles p", "p.user_id = u.id")
*
* 示例3:多条件连接
* db.Table("orders o").
* Join(JoinInner, "customers c", "c.id = o.customer_id AND c.status = ?", "active")
*/
func (d *DB) Join(joinType, table, condition string, params ...interface{}) *DB {
// 启用原生SQL模式
d.rawMode = true
// 处理带参数的连接条件(需要手动处理参数)
if len(params) > 0 {
// 将占位符替换为beego的?格式
condition = strings.Replace(condition, "?", "___", -1) // 临时替换
condition = strings.Replace(condition, "___", "?", -1)
// 添加参数到whereParams(注意顺序)
d.whereParams = append(d.whereParams, params...)
}
d.joins = append(d.joins, JoinInfo{
Type: joinType,
Table: table,
Condition: condition,
})
return d
}
/**
* Where 添加条件,支持多种格式
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:
* Where("id", 1)
* Where("age", ">", 18)
* Where(map[string]interface{}{"name": "张三", "age": 18})
* 当存在JOIN时自动切换到原生SQL模式
*/
func (d *DB) Where(args ...interface{}) *DB {
// 如果已经存在JOIN或者手动启用了原生模式
if d.rawMode {
switch v := args[0].(type) {
case string:
// 字符串格式处理
if len(args) == 2 {
d.whereConditions = append(d.whereConditions, fmt.Sprintf("%s = ?", v))
d.whereParams = append(d.whereParams, args[1])
} else if len(args) == 3 {
operator := args[1].(string)
d.whereConditions = append(d.whereConditions, fmt.Sprintf("%s %s ?", v, operator))
d.whereParams = append(d.whereParams, args[2])
}
case map[string]interface{}:
// Map格式处理
for field, value := range v {
d.whereConditions = append(d.whereConditions, fmt.Sprintf("%s = ?", field))
d.whereParams = append(d.whereParams, value)
}
}
} else {
// 原始QuerySeter处理逻辑
switch v := args[0].(type) {
case string:
if len(args) == 2 {
d.qs = d.qs.Filter(v, args[1])
} else if len(args) == 3 {
operator := args[1].(string)
d.qs = d.qs.Filter(v+"__"+convertOperator(operator), args[2])
}
case map[string]interface{}:
for field, value := range v {
d.qs = d.qs.Filter(field, value)
}
}
}
return d
}
/**
* WhereIn IN条件
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:WhereIn("id", []int{1,2,3})
*/
func (d *DB) WhereIn(field string, values interface{}) *DB {
d.qs = d.qs.Filter(field+"__in", values)
return d
}
/**
* WhereLike 模糊查询
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:
* WhereLike("name", "张")
* WhereLike("*", "张")(需先调用Fields指定字段)
*/
func (d *DB) WhereLike(field string, value string) *DB {
if field == "*" {
cond := orm.NewCondition()
for _, f := range d.fields {
cond = cond.Or(f+"__icontains", value)
}
d.qs = d.qs.SetCond(cond)
} else {
d.qs = d.qs.Filter(field+"__icontains", value)
}
return d
}
/**
* Fields 设置字段(用于全字段模糊查询)
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:Fields("name", "email")
*/
func (d *DB) Fields(fields ...string) *DB {
d.fields = fields
return d
}
/**
* Order 排序
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:Order("id desc")
*/
func (d *DB) Order(order string) *DB {
d.qs = d.qs.OrderBy(order)
return d
}
/**
* Limit 限制条数
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:Limit(10)
*/
func (d *DB) Limit(limit int) *DB {
d.qs = d.qs.Limit(limit)
return d
}
/**
* Page 分页
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users").Page(2, 10)(第二页,每页10条)
* 示例:db.Table("users").Page(2, 10).Select(&users)(第二页,每页10条)
*/
func (d *DB) Page(page, pageSize int) *DB {
return d.Limit(pageSize).Offset((page - 1) * pageSize)
}
/**
* Offset 设置偏移量
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users").Offset(10)(偏移10条)
* 示例:db.Table("users").Offset(10).Select(&users)(偏移10条)
*/
func (d *DB) Offset(offset int) *DB {
d.qs = d.qs.Offset(offset)
return d
}
/**
* Insert 插入单条,返回自增主键
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:user := User{Name: "张三"}; id, err := db.Table("users").Insert(&user)
*/
func (d *DB) Insert(data interface{}) (int64, error) {
return d.ormer.Insert(data)
}
/**
* BatchInsert 批量插入
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:users := []User{{Name: "李四"}, {Name: "王五"}}; rows, err := db.Table("users").BatchInsert(users, 100)
*/
func (d *DB) BatchInsert(data interface{}, batchSize int) (int64, error) {
return d.ormer.InsertMulti(batchSize, data)
}
/**
* Update 更新数据
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users").Where("id", 1).Update(map[string]interface{}{"name": "张三"})
*/
func (d *DB) Update(data map[string]interface{}) (int64, error) {
return d.qs.Update(data)
}
/**
* Delete 删除数据
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users").Where("id", 1).Delete()
*/
func (d *DB) Delete() (int64, error) {
return d.qs.Delete()
}
/**
* BatchDelete 根据主键批量删除
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:db.Table("users").BatchDelete([]int{1,2,3})
*/
func (d *DB) BatchDelete(ids interface{}) (int64, error) {
return d.qs.Filter("id__in", ids).Delete()
}
/**
* Select 增强查询方法(自动处理JOIN查询)
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:var users []User; db.Table("users").Where("age", ">", 18).Select(&users)
*/
func (d *DB) Select(list interface{}) (int64, error) {
if !d.rawMode {
return d.qs.All(list)
}
// 构建SELECT语句
fields := "*"
if len(d.fields) > 0 {
fields = strings.Join(d.fields, ", ")
}
sql := fmt.Sprintf("SELECT %s FROM %s", fields, d.tableName)
// 添加JOIN语句
for _, join := range d.joins {
sql += fmt.Sprintf(" %s JOIN %s ON %s", join.Type, join.Table, join.Condition)
}
// 处理WHERE条件
if len(d.whereConditions) > 0 {
sql += " WHERE " + strings.Join(d.whereConditions, " AND ")
}
// 处理ORDER BY
if d.orderBy != "" {
sql += " ORDER BY " + d.orderBy
}
// 处理LIMIT和OFFSET(关键修改点)
if d.limit > 0 {
sql += fmt.Sprintf(" LIMIT %d", d.limit)
}
if d.offset > 0 {
sql += fmt.Sprintf(" OFFSET %d", d.offset)
}
// 执行查询(移除了SetMaxRows)
rawSeter := d.ormer.Raw(sql, d.whereParams...)
return rawSeter.QueryRows(list)
}
/**
* Find 查询单条
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:var user User; db.Table("users").Where("id", 1).Find(&user)
*/
func (d *DB) Find(obj interface{}) error {
if !d.rawMode {
return d.qs.One(obj)
}
// 构建基础查询
fields := "*"
if len(d.fields) > 0 {
fields = strings.Join(d.fields, ", ")
}
sql := fmt.Sprintf("SELECT %s FROM %s", fields, d.tableName)
// 添加JOIN
for _, join := range d.joins {
sql += fmt.Sprintf(" %s JOIN %s ON %s", join.Type, join.Table, join.Condition)
}
// 处理WHERE
if len(d.whereConditions) > 0 {
sql += " WHERE " + strings.Join(d.whereConditions, " AND ")
}
// 添加LIMIT 1
sql += " LIMIT 1"
return d.ormer.Raw(sql, d.whereParams...).QueryRow(obj)
}
/**
* Count 统计数量
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:total, err := db.Table("users").Where("age", ">", 18).Count()
*/
func (d *DB) Count() (int64, error) {
if !d.rawMode {
return d.qs.Count()
}
sql := fmt.Sprintf("SELECT COUNT(*) FROM %s", d.tableName)
// 添加JOIN
for _, join := range d.joins {
sql += fmt.Sprintf(" %s JOIN %s ON %s", join.Type, join.Table, join.Condition)
}
// 处理WHERE
if len(d.whereConditions) > 0 {
sql += " WHERE " + strings.Join(d.whereConditions, " AND ")
}
var count int64
err := d.ormer.Raw(sql, d.whereParams...).QueryRow(&count)
return count, err
}
/**
* Cursor 游标查询
* @Author Xven <[email protected]>
* @param {int} limit 每页限制条数
* @param {int} offset 偏移量
* @return {int64, error}
* 示例:var results []User; db.Table("users").Cursor(10, 0).Select(&results)
*/
func (d *DB) Cursor(limit int, offset int) *DB {
d.qs = d.qs.Limit(limit).Offset(offset)
return d
}
/**
* Paginate 分页查询
* @Author Xven <[email protected]>
* @param {int} page 当前页码
* @param {int} pageSize 每页限制条数
* @return {int64, error}
* 示例:var results []User; total, err := db.Table("users").Paginate(1, 10).Select(&results)
*/
func (d *DB) Paginate(page int, pageSize int) *DB {
d.qs = d.qs.Limit(pageSize).Offset((page - 1) * pageSize)
return d
}
/**
* Max 查询指定字段的最大值
* @Author Xven <[email protected]>
* @param {string} field 指定的字段名
* @return {float64, error} 返回最大值和可能出现的错误
* 示例:maxValue, err := db.Table("xven_menus").Where("parent_id", parentID).Max("id")
*/
func (d *DB) Max(field string) (float64, error) {
var result float64
sql := "SELECT MAX(" + field + ") FROM " + d.tableName
// 假设当前的查询条件需要应用到 SQL 中,这里简单拼接
if d.qs != nil {
// 这里需要更复杂的逻辑来处理查询条件,示例只是简单示意
// 实际应用中需要处理更多的查询条件类型和格式
sql += " WHERE ..."
}
// 修复:d.ormer.Raw(sql).QueryRow 只返回一个 error,去掉 num 变量
err := d.ormer.Raw(sql).QueryRow(&result)
if err != nil {
return 0, err
}
return result, nil
}
/**
* Exists 检查查询结果是否存在
* @Author Xven <[email protected]>
* @param 无
* @return {bool, error} 返回是否存在和可能出现的错误
* 示例:exists, err := db.Table("xven_menus").Where("parent_id", parentID).Exists()
*/
func (d *DB) Exists() (bool, error) {
count, err := d.qs.Count()
if err != nil {
return false, err
}
return count > 0, nil
}
/**
* 转换操作符到orm支持的格式
* @Author Xven <[email protected]>
* @param (?1:)
* @return (?1:)
* 示例:convertOperator(">")
*/
func convertOperator(op string) string {
switch op {
case ">":
return "gt"
case "<":
return "lt"
case ">=":
return "gte"
case "<=":
return "lte"
case "!=":
return "ne"
case "in":
return "in"
case "like":
return "icontains"
default:
return ""
}
}
使用示例
Go
// 初始化
db := NewDB()
// 简单条件查询
db.Table("users").Where("id", 1)
// 比较运算
db.Table("users").Where("age", ">", 18)
// 多条件查询
db.Table("users").Where(map[string]interface{}{"name": "张三", "age": 18})
// IN查询
db.Table("users").WhereIn("id", []int{1,2,3})
// 单字段模糊查询
db.Table("users").WhereLike("name", "张")
// 全字段模糊查询
db.Table("users").Fields("name", "email").WhereLike("*", "张")
// 排序
db.Table("users").Order("id desc")
// 分页
var users []User
db.Table("users").Page(2, 10).Select(&users)
// 删除
db.Table("users").WhereIn("id", []int{1,2,3}).Delete()
// 插入并返回ID
user := User{Name: "张三"}
id, _ := db.Table("users").Insert(&user)
// 批量插入
users := []User{{Name: "李四"}, {Name: "王五"}}
db.Table("users").BatchInsert(users, 100)
// 游标查询
var results []User
db.Table("users").Cursor(10, 0).Select(&results)
// 分页查询
var results []User
total, _ := db.Table("users").Paginate(1, 10).Select(&results)
// 统计数量
total, _ := db.Table("users").Count()
// 批量删除
db.Table("users").BatchDelete([]int{1,2,3})
// 更新
db.Table("users").Where("id", 1).Update(map[string]interface{}{"name": "张三"})
// 查询单条
var user User
db.Table("users").Where("id", 1).Find(&user)
// 查询多条
var users []User
db.Table("users").Where("age", ">", 18).Select(&users)
// 基础INNER JOIN
var orders []Order
db.Table("orders").
Join(JoinInner, "customers", "customers.id = orders.customer_id").
Where("customers.status = ?", "active").
Select(&orders)
// 多表JOIN带别名
var results []struct {
UserName string
OrderID int
Product string
}
db.Table("users u").
Join(JoinLeft, "orders o", "o.user_id = u.id").
Join(JoinInner, "products p", "p.order_id = o.id").
Fields("u.name as user_name", "o.id as order_id", "p.product_name").
Where("u.created_at > ?", "2023-01-01").
Order("u.name ASC").
Limit(10).
Select(&results)
// 带参数的复杂JOIN条件
var logs []LoginLog
db.Table("users u").
Join(JoinLeft, "login_logs l", "l.user_id = u.id AND l.login_time > ?", "2023-06-01").
Where("u.status = ?", 1).
Select(&logs)
// 统计关联数据量
total, _ := db.Table("departments d").
Join(JoinLeft, "employees e", "e.department_id = d.id").
Where("d.company_id = ?", 123).
Count()