feat(request): 实现请求参数获取方法
- 完成 ReqParam/ReqParams 方法实现,用于获取 URL 参数并返回 *Obj - 完成 ReqForm/ReqForms 方法实现,用于获取表单数据并返回 *Obj - 完成 ReqJson/ReqJsons 方法实现,用于获取 JSON Body 并返回 *Obj - 完成 ReqFile/ReqFiles 方法实现,用于获取上传文件 - 完成 ReqData/ReqDatas 方法实现,用于统一封装请求数据获取并返回 *Obj - 更新计划文件状态,标记所有相关功能模块为已完成
This commit is contained in:
+250
-310
@@ -2,7 +2,7 @@
|
||||
|
||||
## 概述
|
||||
|
||||
HoTimeDB是一个基于Golang实现的轻量级ORM框架,参考PHP Medoo设计,提供简洁的数据库操作接口。支持MySQL、SQLite等数据库,并集成了缓存、事务、链式查询等功能。
|
||||
HoTimeDB是一个基于Golang实现的轻量级ORM框架,参考PHP Medoo设计,提供简洁的数据库操作接口。支持MySQL、SQLite、PostgreSQL等数据库,并集成了缓存、事务、链式查询等功能。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -12,7 +12,9 @@ HoTimeDB是一个基于Golang实现的轻量级ORM框架,参考PHP Medoo设计
|
||||
- [查询(Select)](#查询select)
|
||||
- [获取单条记录(Get)](#获取单条记录get)
|
||||
- [插入(Insert)](#插入insert)
|
||||
- [批量插入(BatchInsert)](#批量插入batchinsert)
|
||||
- [更新(Update)](#更新update)
|
||||
- [Upsert操作](#upsert操作)
|
||||
- [删除(Delete)](#删除delete)
|
||||
- [链式查询构建器](#链式查询构建器)
|
||||
- [条件查询语法](#条件查询语法)
|
||||
@@ -21,6 +23,7 @@ HoTimeDB是一个基于Golang实现的轻量级ORM框架,参考PHP Medoo设计
|
||||
- [聚合函数](#聚合函数)
|
||||
- [事务处理](#事务处理)
|
||||
- [缓存机制](#缓存机制)
|
||||
- [PostgreSQL支持](#postgresql支持)
|
||||
- [高级特性](#高级特性)
|
||||
|
||||
## 快速开始
|
||||
@@ -44,8 +47,10 @@ func createConnection() (master, slave *sql.DB) {
|
||||
}
|
||||
|
||||
// 初始化HoTimeDB
|
||||
db := &db.HoTimeDB{}
|
||||
db.SetConnect(createConnection)
|
||||
database := &db.HoTimeDB{
|
||||
Type: "mysql", // 可选:mysql, sqlite3, postgres
|
||||
}
|
||||
database.SetConnect(createConnection)
|
||||
```
|
||||
|
||||
## 数据库配置
|
||||
@@ -59,7 +64,7 @@ type HoTimeDB struct {
|
||||
DBName string
|
||||
*cache.HoTimeCache
|
||||
Log *logrus.Logger
|
||||
Type string // 数据库类型
|
||||
Type string // 数据库类型:mysql, sqlite3, postgres
|
||||
Prefix string // 表前缀
|
||||
LastQuery string // 最后执行的SQL
|
||||
LastData []interface{} // 最后的参数
|
||||
@@ -69,19 +74,20 @@ type HoTimeDB struct {
|
||||
*sql.Tx // 事务对象
|
||||
SlaveDB *sql.DB // 从数据库
|
||||
Mode int // 0生产模式,1测试模式,2开发模式
|
||||
Dialect Dialect // 数据库方言适配器
|
||||
}
|
||||
```
|
||||
|
||||
### 设置表前缀
|
||||
|
||||
```go
|
||||
db.Prefix = "app_"
|
||||
database.Prefix = "app_"
|
||||
```
|
||||
|
||||
### 设置运行模式
|
||||
|
||||
```go
|
||||
db.Mode = 2 // 开发模式,会输出SQL日志
|
||||
database.Mode = 2 // 开发模式,会输出SQL日志
|
||||
```
|
||||
|
||||
## 基本操作
|
||||
@@ -92,35 +98,40 @@ db.Mode = 2 // 开发模式,会输出SQL日志
|
||||
|
||||
```go
|
||||
// 查询所有字段
|
||||
users := db.Select("user")
|
||||
users := database.Select("user")
|
||||
|
||||
// 查询指定字段
|
||||
users := db.Select("user", "id,name,email")
|
||||
users := database.Select("user", "id,name,email")
|
||||
|
||||
// 查询指定字段(数组形式)
|
||||
users := db.Select("user", []string{"id", "name", "email"})
|
||||
users := database.Select("user", []string{"id", "name", "email"})
|
||||
|
||||
// 单条件查询
|
||||
users := db.Select("user", "*", common.Map{
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
|
||||
// 多条件查询(必须使用AND包装)
|
||||
users = db.Select("user", "*", common.Map{
|
||||
"AND": common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
},
|
||||
// 多条件查询(自动用 AND 连接)
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
})
|
||||
// 生成: WHERE `status`=? AND `age`>?
|
||||
```
|
||||
|
||||
#### 复杂条件查询
|
||||
|
||||
**重要说明:多个条件必须使用AND或OR包装,不能直接在根Map中写多个字段条件**
|
||||
|
||||
```go
|
||||
// AND条件(多个条件必须用AND包装)
|
||||
users := db.Select("user", "*", common.Map{
|
||||
// 简化语法:多条件自动用 AND 连接
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
"name[~]": "张",
|
||||
})
|
||||
// 生成: WHERE `status`=? AND `age`>? AND `name` LIKE ?
|
||||
|
||||
// 显式 AND 条件(与上面等效)
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"AND": common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
@@ -128,16 +139,16 @@ users := db.Select("user", "*", common.Map{
|
||||
},
|
||||
})
|
||||
|
||||
// OR条件
|
||||
users := db.Select("user", "*", common.Map{
|
||||
// OR 条件
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"OR": common.Map{
|
||||
"status": 1,
|
||||
"type": 2,
|
||||
},
|
||||
})
|
||||
|
||||
// 混合条件(嵌套AND/OR)
|
||||
users := db.Select("user", "*", common.Map{
|
||||
// 混合条件(嵌套 AND/OR)
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"AND": common.Map{
|
||||
"status": 1,
|
||||
"OR": common.Map{
|
||||
@@ -147,18 +158,16 @@ users := db.Select("user", "*", common.Map{
|
||||
},
|
||||
})
|
||||
|
||||
// 带ORDER BY、LIMIT等特殊条件
|
||||
users := db.Select("user", "*", common.Map{
|
||||
"AND": common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
},
|
||||
"ORDER": "id DESC",
|
||||
"LIMIT": 10,
|
||||
// 带 ORDER BY、LIMIT 等特殊条件(关键字支持大小写)
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"status": 1,
|
||||
"age[>]": 18,
|
||||
"ORDER": "id DESC", // 或 "order": "id DESC"
|
||||
"LIMIT": 10, // 或 "limit": 10
|
||||
})
|
||||
|
||||
// 带多个特殊条件
|
||||
users := db.Select("user", "*", common.Map{
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"OR": common.Map{
|
||||
"level": "vip",
|
||||
"balance[>]": 1000,
|
||||
@@ -167,18 +176,33 @@ users := db.Select("user", "*", common.Map{
|
||||
"GROUP": "department",
|
||||
"LIMIT": []int{0, 20}, // offset 0, limit 20
|
||||
})
|
||||
|
||||
// 使用 HAVING 过滤分组结果
|
||||
users := database.Select("user", "dept_id, COUNT(*) as cnt", common.Map{
|
||||
"GROUP": "dept_id",
|
||||
"HAVING": common.Map{
|
||||
"cnt[>]": 5,
|
||||
},
|
||||
})
|
||||
|
||||
// 使用独立 OFFSET
|
||||
users := database.Select("user", "*", common.Map{
|
||||
"status": 1,
|
||||
"LIMIT": 10,
|
||||
"OFFSET": 20,
|
||||
})
|
||||
```
|
||||
|
||||
### 获取单条记录(Get)
|
||||
|
||||
```go
|
||||
// 获取单个用户
|
||||
user := db.Get("user", "*", common.Map{
|
||||
user := database.Get("user", "*", common.Map{
|
||||
"id": 1,
|
||||
})
|
||||
|
||||
// 获取指定字段
|
||||
user := db.Get("user", "id,name,email", common.Map{
|
||||
user := database.Get("user", "id,name,email", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
```
|
||||
@@ -187,7 +211,7 @@ user := db.Get("user", "id,name,email", common.Map{
|
||||
|
||||
```go
|
||||
// 基本插入
|
||||
id := db.Insert("user", common.Map{
|
||||
id := database.Insert("user", common.Map{
|
||||
"name": "张三",
|
||||
"email": "zhangsan@example.com",
|
||||
"age": 25,
|
||||
@@ -199,11 +223,31 @@ id := db.Insert("user", common.Map{
|
||||
fmt.Println("插入的用户ID:", id)
|
||||
```
|
||||
|
||||
### 批量插入(BatchInsert)
|
||||
|
||||
```go
|
||||
// 批量插入多条记录(使用 []Map 格式,更直观)
|
||||
affected := database.BatchInsert("user", []common.Map{
|
||||
{"name": "张三", "email": "zhang@example.com", "age": 25},
|
||||
{"name": "李四", "email": "li@example.com", "age": 30},
|
||||
{"name": "王五", "email": "wang@example.com", "age": 28},
|
||||
})
|
||||
// 生成: INSERT INTO `user` (`age`, `email`, `name`) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)
|
||||
|
||||
fmt.Printf("批量插入 %d 条记录\n", affected)
|
||||
|
||||
// 支持 [#] 标记直接插入 SQL 表达式
|
||||
affected := database.BatchInsert("log", []common.Map{
|
||||
{"user_id": 1, "action": "login", "created_time[#]": "NOW()"},
|
||||
{"user_id": 2, "action": "logout", "created_time[#]": "NOW()"},
|
||||
})
|
||||
```
|
||||
|
||||
### 更新(Update)
|
||||
|
||||
```go
|
||||
// 基本更新
|
||||
affected := db.Update("user", common.Map{
|
||||
affected := database.Update("user", common.Map{
|
||||
"name": "李四",
|
||||
"email": "lisi@example.com",
|
||||
"updated_time[#]": "NOW()",
|
||||
@@ -211,8 +255,8 @@ affected := db.Update("user", common.Map{
|
||||
"id": 1,
|
||||
})
|
||||
|
||||
// 条件更新
|
||||
affected := db.Update("user", common.Map{
|
||||
// 条件更新(多条件自动 AND 连接)
|
||||
affected := database.Update("user", common.Map{
|
||||
"status": 0,
|
||||
}, common.Map{
|
||||
"age[<]": 18,
|
||||
@@ -222,16 +266,60 @@ affected := db.Update("user", common.Map{
|
||||
fmt.Println("更新的记录数:", affected)
|
||||
```
|
||||
|
||||
### Upsert操作
|
||||
|
||||
Upsert(插入或更新):如果记录存在则更新,不存在则插入。
|
||||
|
||||
```go
|
||||
// Upsert 操作(使用 Slice 格式)
|
||||
affected := database.Upsert("user",
|
||||
common.Map{
|
||||
"id": 1,
|
||||
"name": "张三",
|
||||
"email": "zhang@example.com",
|
||||
"login_count": 1,
|
||||
},
|
||||
common.Slice{"id"}, // 唯一键(用于冲突检测)
|
||||
common.Slice{"name", "email", "login_count"}, // 冲突时更新的字段
|
||||
)
|
||||
|
||||
// MySQL 生成:
|
||||
// INSERT INTO user (id,name,email,login_count) VALUES (?,?,?,?)
|
||||
// ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email), login_count=VALUES(login_count)
|
||||
|
||||
// PostgreSQL 生成:
|
||||
// INSERT INTO "user" (id,name,email,login_count) VALUES ($1,$2,$3,$4)
|
||||
// ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name, email=EXCLUDED.email, login_count=EXCLUDED.login_count
|
||||
|
||||
// 使用 [#] 标记直接 SQL 更新
|
||||
affected := database.Upsert("user",
|
||||
common.Map{
|
||||
"id": 1,
|
||||
"name": "张三",
|
||||
"login_count[#]": "login_count + 1", // 直接 SQL 表达式
|
||||
},
|
||||
common.Slice{"id"},
|
||||
common.Slice{"name", "login_count"},
|
||||
)
|
||||
|
||||
// 也支持可变参数形式
|
||||
affected := database.Upsert("user",
|
||||
common.Map{"id": 1, "name": "张三"},
|
||||
common.Slice{"id"},
|
||||
"name", "email", // 可变参数
|
||||
)
|
||||
```
|
||||
|
||||
### 删除(Delete)
|
||||
|
||||
```go
|
||||
// 根据ID删除
|
||||
affected := db.Delete("user", common.Map{
|
||||
affected := database.Delete("user", common.Map{
|
||||
"id": 1,
|
||||
})
|
||||
|
||||
// 条件删除
|
||||
affected := db.Delete("user", common.Map{
|
||||
// 条件删除(多条件自动 AND 连接)
|
||||
affected := database.Delete("user", common.Map{
|
||||
"status": 0,
|
||||
"created_time[<]": "2023-01-01",
|
||||
})
|
||||
@@ -245,7 +333,7 @@ HoTimeDB提供了链式查询构建器,让查询更加直观:
|
||||
|
||||
```go
|
||||
// 基本链式查询
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
Where("status", 1).
|
||||
And("age[>]", 18).
|
||||
Order("created_time DESC").
|
||||
@@ -253,12 +341,12 @@ users := db.Table("user").
|
||||
Select()
|
||||
|
||||
// 链式获取单条记录
|
||||
user := db.Table("user").
|
||||
user := database.Table("user").
|
||||
Where("id", 1).
|
||||
Get()
|
||||
|
||||
// 链式更新
|
||||
affected := db.Table("user").
|
||||
affected := database.Table("user").
|
||||
Where("id", 1).
|
||||
Update(common.Map{
|
||||
"name": "新名称",
|
||||
@@ -266,12 +354,12 @@ affected := db.Table("user").
|
||||
})
|
||||
|
||||
// 链式删除
|
||||
affected := db.Table("user").
|
||||
affected := database.Table("user").
|
||||
Where("status", 0).
|
||||
Delete()
|
||||
|
||||
// 链式统计
|
||||
count := db.Table("user").
|
||||
count := database.Table("user").
|
||||
Where("status", 1).
|
||||
Count()
|
||||
```
|
||||
@@ -280,7 +368,7 @@ count := db.Table("user").
|
||||
|
||||
```go
|
||||
// 复杂条件组合
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
Where("status", 1).
|
||||
And("age[>=]", 18).
|
||||
Or(common.Map{
|
||||
@@ -289,7 +377,9 @@ users := db.Table("user").
|
||||
}).
|
||||
Order("created_time DESC", "id ASC").
|
||||
Group("department").
|
||||
Having(common.Map{"COUNT(*).[>]": 5}). // 新增 HAVING 支持
|
||||
Limit(0, 20).
|
||||
Offset(10). // 新增独立 OFFSET 支持
|
||||
Select("id,name,email,age")
|
||||
```
|
||||
|
||||
@@ -384,24 +474,24 @@ HoTimeDB支持丰富的条件查询语法,类似于Medoo:
|
||||
|
||||
```go
|
||||
// LEFT JOIN
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
LeftJoin("profile", "user.id = profile.user_id").
|
||||
LeftJoin("department", "user.dept_id = department.id").
|
||||
Where("user.status", 1).
|
||||
Select("user.*, profile.avatar, department.name AS dept_name")
|
||||
|
||||
// RIGHT JOIN
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
RightJoin("order", "user.id = order.user_id").
|
||||
Select()
|
||||
|
||||
// INNER JOIN
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
InnerJoin("profile", "user.id = profile.user_id").
|
||||
Select()
|
||||
|
||||
// FULL JOIN
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
FullJoin("profile", "user.id = profile.user_id").
|
||||
Select()
|
||||
```
|
||||
@@ -409,7 +499,7 @@ users := db.Table("user").
|
||||
### 传统JOIN语法
|
||||
|
||||
```go
|
||||
users := db.Select("user",
|
||||
users := database.Select("user",
|
||||
common.Slice{
|
||||
common.Map{"[>]profile": "user.id = profile.user_id"},
|
||||
common.Map{"[>]department": "user.dept_id = department.id"},
|
||||
@@ -434,12 +524,12 @@ users := db.Select("user",
|
||||
|
||||
```go
|
||||
// 设置分页:页码3,每页20条
|
||||
users := db.Page(3, 20).PageSelect("user", "*", common.Map{
|
||||
users := database.Page(3, 20).PageSelect("user", "*", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
|
||||
// 链式分页
|
||||
users := db.Table("user").
|
||||
users := database.Table("user").
|
||||
Where("status", 1).
|
||||
Page(2, 15). // 第2页,每页15条
|
||||
Select()
|
||||
@@ -449,7 +539,7 @@ users := db.Table("user").
|
||||
|
||||
```go
|
||||
// 获取总数
|
||||
total := db.Count("user", common.Map{
|
||||
total := database.Count("user", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
|
||||
@@ -468,15 +558,15 @@ fmt.Printf("总记录数: %d, 总页数: %d, 当前页: %d\n", total, totalPages
|
||||
|
||||
```go
|
||||
// 总数统计
|
||||
total := db.Count("user")
|
||||
total := database.Count("user")
|
||||
|
||||
// 条件统计
|
||||
activeUsers := db.Count("user", common.Map{
|
||||
activeUsers := database.Count("user", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
|
||||
// JOIN统计
|
||||
count := db.Count("user",
|
||||
count := database.Count("user",
|
||||
common.Slice{
|
||||
common.Map{"[>]profile": "user.id = profile.user_id"},
|
||||
},
|
||||
@@ -491,31 +581,47 @@ count := db.Count("user",
|
||||
|
||||
```go
|
||||
// 基本求和
|
||||
totalAmount := db.Sum("order", "amount")
|
||||
totalAmount := database.Sum("order", "amount")
|
||||
|
||||
// 条件求和
|
||||
paidAmount := db.Sum("order", "amount", common.Map{
|
||||
paidAmount := database.Sum("order", "amount", common.Map{
|
||||
"status": "paid",
|
||||
"created_time[>]": "2023-01-01",
|
||||
})
|
||||
```
|
||||
|
||||
// JOIN求和
|
||||
sum := db.Sum("order", "amount",
|
||||
common.Slice{
|
||||
common.Map{"[>]user": "order.user_id = user.id"},
|
||||
},
|
||||
common.Map{
|
||||
"user.level": "vip",
|
||||
"order.status": "paid",
|
||||
},
|
||||
)
|
||||
### 平均值
|
||||
|
||||
```go
|
||||
// 基本平均值
|
||||
avgAge := database.Avg("user", "age")
|
||||
|
||||
// 条件平均值
|
||||
avgAge := database.Avg("user", "age", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
```
|
||||
|
||||
### 最大值/最小值
|
||||
|
||||
```go
|
||||
// 最大值
|
||||
maxAge := database.Max("user", "age")
|
||||
|
||||
// 最小值
|
||||
minAge := database.Min("user", "age")
|
||||
|
||||
// 条件最大值
|
||||
maxBalance := database.Max("user", "balance", common.Map{
|
||||
"status": 1,
|
||||
})
|
||||
```
|
||||
|
||||
## 事务处理
|
||||
|
||||
```go
|
||||
// 事务操作
|
||||
success := db.Action(func(tx db.HoTimeDB) bool {
|
||||
success := database.Action(func(tx db.HoTimeDB) bool {
|
||||
// 在事务中执行多个操作
|
||||
|
||||
// 扣减用户余额
|
||||
@@ -541,18 +647,6 @@ success := db.Action(func(tx db.HoTimeDB) bool {
|
||||
return false // 回滚
|
||||
}
|
||||
|
||||
// 添加订单详情
|
||||
detailId := tx.Insert("order_detail", common.Map{
|
||||
"order_id": orderId,
|
||||
"product_id": 1001,
|
||||
"quantity": 1,
|
||||
"price": 100,
|
||||
})
|
||||
|
||||
if detailId == 0 {
|
||||
return false // 回滚
|
||||
}
|
||||
|
||||
return true // 提交
|
||||
})
|
||||
|
||||
@@ -560,7 +654,7 @@ if success {
|
||||
fmt.Println("事务执行成功")
|
||||
} else {
|
||||
fmt.Println("事务回滚")
|
||||
fmt.Println("错误:", db.LastErr.GetError())
|
||||
fmt.Println("错误:", database.LastErr.GetError())
|
||||
}
|
||||
```
|
||||
|
||||
@@ -574,7 +668,7 @@ HoTimeDB集成了缓存功能,可以自动缓存查询结果:
|
||||
import "code.hoteas.com/golang/hotime/cache"
|
||||
|
||||
// 设置缓存
|
||||
db.HoTimeCache = &cache.HoTimeCache{
|
||||
database.HoTimeCache = &cache.HoTimeCache{
|
||||
// 缓存配置
|
||||
}
|
||||
```
|
||||
@@ -590,21 +684,55 @@ db.HoTimeCache = &cache.HoTimeCache{
|
||||
|
||||
```go
|
||||
// 手动清除表缓存
|
||||
db.HoTimeCache.Db("user*", nil) // 清除user表所有缓存
|
||||
database.HoTimeCache.Db("user*", nil) // 清除user表所有缓存
|
||||
```
|
||||
|
||||
## PostgreSQL支持
|
||||
|
||||
HoTimeDB 支持 PostgreSQL 数据库,自动处理语法差异。
|
||||
|
||||
### PostgreSQL 配置
|
||||
|
||||
```go
|
||||
import (
|
||||
"code.hoteas.com/golang/hotime/db"
|
||||
_ "github.com/lib/pq" // PostgreSQL 驱动
|
||||
)
|
||||
|
||||
database := &db.HoTimeDB{
|
||||
Type: "postgres", // 设置数据库类型为 postgres
|
||||
Prefix: "app_",
|
||||
}
|
||||
|
||||
database.SetConnect(func(err ...*common.Error) (master, slave *sql.DB) {
|
||||
dsn := "host=localhost port=5432 user=postgres password=secret dbname=mydb sslmode=disable"
|
||||
master, _ = sql.Open("postgres", dsn)
|
||||
return master, master
|
||||
})
|
||||
```
|
||||
|
||||
### 主要差异
|
||||
|
||||
| 特性 | MySQL | PostgreSQL |
|
||||
|------|-------|------------|
|
||||
| 标识符引号 | \`name\` | "name" |
|
||||
| 占位符 | ? | $1, $2, $3... |
|
||||
| Upsert | ON DUPLICATE KEY UPDATE | ON CONFLICT DO UPDATE |
|
||||
|
||||
所有这些差异由框架自动处理,无需手动调整代码。
|
||||
|
||||
## 高级特性
|
||||
|
||||
### 调试模式
|
||||
|
||||
```go
|
||||
// 设置调试模式
|
||||
db.Mode = 2
|
||||
database.Mode = 2
|
||||
|
||||
// 查看最后执行的SQL
|
||||
fmt.Println("最后的SQL:", db.LastQuery)
|
||||
fmt.Println("参数:", db.LastData)
|
||||
fmt.Println("错误:", db.LastErr.GetError())
|
||||
fmt.Println("最后的SQL:", database.LastQuery)
|
||||
fmt.Println("参数:", database.LastData)
|
||||
fmt.Println("错误:", database.LastErr.GetError())
|
||||
```
|
||||
|
||||
### 主从分离
|
||||
@@ -620,7 +748,7 @@ func createConnection() (master, slave *sql.DB) {
|
||||
return master, slave
|
||||
}
|
||||
|
||||
db.SetConnect(createConnection)
|
||||
database.SetConnect(createConnection)
|
||||
// 查询会自动使用从库,增删改使用主库
|
||||
```
|
||||
|
||||
@@ -628,97 +756,16 @@ db.SetConnect(createConnection)
|
||||
|
||||
```go
|
||||
// 执行查询SQL
|
||||
results := db.Query("SELECT * FROM user WHERE age > ? AND status = ?", 18, 1)
|
||||
results := database.Query("SELECT * FROM user WHERE age > ? AND status = ?", 18, 1)
|
||||
|
||||
// 执行更新SQL
|
||||
result, err := db.Exec("UPDATE user SET last_login = NOW() WHERE id = ?", 1)
|
||||
result, err := database.Exec("UPDATE user SET last_login = NOW() WHERE id = ?", 1)
|
||||
if err.GetError() == nil {
|
||||
affected, _ := result.RowsAffected()
|
||||
fmt.Println("影响行数:", affected)
|
||||
}
|
||||
```
|
||||
|
||||
### 数据类型处理
|
||||
|
||||
```go
|
||||
// 时间戳插入
|
||||
db.Insert("log", common.Map{
|
||||
"user_id": 1,
|
||||
"action": "login",
|
||||
"created_time[#]": "UNIX_TIMESTAMP()",
|
||||
})
|
||||
|
||||
// JSON数据
|
||||
db.Insert("user", common.Map{
|
||||
"name": "张三",
|
||||
"preferences": `{"theme": "dark", "language": "zh-CN"}`,
|
||||
})
|
||||
```
|
||||
|
||||
### 数据行处理
|
||||
|
||||
HoTimeDB内部的`Row`方法会自动处理不同数据类型:
|
||||
|
||||
```go
|
||||
// 自动转换[]uint8为字符串
|
||||
// 保持其他类型的原始值
|
||||
// 处理NULL值
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
```go
|
||||
// 检查错误
|
||||
users := db.Select("user", "*", common.Map{"status": 1})
|
||||
if db.LastErr.GetError() != nil {
|
||||
fmt.Println("查询错误:", db.LastErr.GetError())
|
||||
return
|
||||
}
|
||||
|
||||
// 插入时检查错误
|
||||
id := db.Insert("user", common.Map{
|
||||
"name": "test",
|
||||
"email": "test@example.com",
|
||||
})
|
||||
|
||||
if id == 0 && db.LastErr.GetError() != nil {
|
||||
fmt.Println("插入失败:", db.LastErr.GetError())
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### IN查询优化
|
||||
|
||||
HoTimeDB会自动优化IN查询,将连续的数字转换为BETWEEN查询以提高性能:
|
||||
|
||||
```go
|
||||
// 这个查询会被自动优化(单个IN条件)
|
||||
users := db.Select("user", "*", common.Map{
|
||||
"id": []int{1, 2, 3, 4, 5, 10, 11, 12},
|
||||
// 自动转为 (id BETWEEN 1 AND 5) OR (id BETWEEN 10 AND 12)
|
||||
})
|
||||
```
|
||||
|
||||
### 批量操作
|
||||
|
||||
```go
|
||||
// 使用事务进行批量插入
|
||||
success := db.Action(func(tx db.HoTimeDB) bool {
|
||||
for i := 0; i < 1000; i++ {
|
||||
id := tx.Insert("user", common.Map{
|
||||
"name": fmt.Sprintf("User%d", i),
|
||||
"email": fmt.Sprintf("user%d@example.com", i),
|
||||
"created_time[#]": "NOW()",
|
||||
})
|
||||
if id == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
```
|
||||
|
||||
## 特殊语法详解
|
||||
|
||||
### 条件标记符说明
|
||||
@@ -741,150 +788,43 @@ success := db.Action(func(tx db.HoTimeDB) bool {
|
||||
| `[#!]` | 不等于直接SQL | `"status[#!]": "1"` | `status != 1` |
|
||||
| `[!#]` | 不等于直接SQL | `"status[!#]": "1"` | `status != 1` |
|
||||
|
||||
## 与PHP Medoo的差异
|
||||
### 特殊关键字(支持大小写)
|
||||
|
||||
1. **类型系统**: Golang的强类型要求使用`common.Map`和`common.Slice`
|
||||
2. **语法差异**: 某些条件语法可能略有不同
|
||||
3. **错误处理**: 使用Golang的错误处理模式
|
||||
4. **并发安全**: 需要注意并发使用时的安全性
|
||||
5. **缓存集成**: 内置了缓存功能
|
||||
6. **链式调用**: 提供了更丰富的链式API
|
||||
|
||||
## 完整示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"database/sql"
|
||||
"code.hoteas.com/golang/hotime/db"
|
||||
"code.hoteas.com/golang/hotime/common"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 初始化数据库
|
||||
database := &db.HoTimeDB{
|
||||
Prefix: "app_",
|
||||
Mode: 2, // 开发模式
|
||||
}
|
||||
|
||||
database.SetConnect(func(err ...*common.Error) (master, slave *sql.DB) {
|
||||
master, _ = sql.Open("mysql", "root:password@tcp(localhost:3306)/testdb")
|
||||
return master, master
|
||||
})
|
||||
|
||||
// 查询用户列表
|
||||
users := database.Table("user").
|
||||
Where("status", 1).
|
||||
And("age[>=]", 18).
|
||||
Order("created_time DESC").
|
||||
Limit(0, 10).
|
||||
Select("id,name,email,age")
|
||||
|
||||
for _, user := range users {
|
||||
fmt.Printf("用户: %s, 邮箱: %s, 年龄: %v\n",
|
||||
user.GetString("name"),
|
||||
user.GetString("email"),
|
||||
user.Get("age"))
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
userId := database.Insert("user", common.Map{
|
||||
"name": "新用户",
|
||||
"email": "new@example.com",
|
||||
"age": 25,
|
||||
"status": 1,
|
||||
"created_time[#]": "NOW()",
|
||||
})
|
||||
|
||||
fmt.Printf("创建用户ID: %d\n", userId)
|
||||
|
||||
// 更新用户
|
||||
affected := database.Table("user").
|
||||
Where("id", userId).
|
||||
Update(common.Map{
|
||||
"last_login[#]": "NOW()",
|
||||
"login_count[#]": "login_count + 1",
|
||||
})
|
||||
|
||||
fmt.Printf("更新记录数: %d\n", affected)
|
||||
|
||||
// 复杂查询示例
|
||||
orders := database.Table("order").
|
||||
LeftJoin("user", "order.user_id = user.id").
|
||||
LeftJoin("product", "order.product_id = product.id").
|
||||
Where("order.status", "paid").
|
||||
And("order.created_time[>]", "2023-01-01").
|
||||
And(common.Map{
|
||||
"OR": common.Map{
|
||||
"user.level": "vip",
|
||||
"order.amount[>]": 1000,
|
||||
},
|
||||
}).
|
||||
Order("order.created_time DESC").
|
||||
Group("user.id").
|
||||
Select("user.name, user.email, SUM(order.amount) as total_amount, COUNT(*) as order_count")
|
||||
|
||||
// 事务示例
|
||||
success := database.Action(func(tx db.HoTimeDB) bool {
|
||||
// 在事务中执行操作
|
||||
orderId := tx.Insert("order", common.Map{
|
||||
"user_id": userId,
|
||||
"total": 100.50,
|
||||
"status": "pending",
|
||||
"created_time[#]": "NOW()",
|
||||
})
|
||||
|
||||
if orderId == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
detailId := tx.Insert("order_detail", common.Map{
|
||||
"order_id": orderId,
|
||||
"product_id": 1,
|
||||
"quantity": 2,
|
||||
"price": 50.25,
|
||||
})
|
||||
|
||||
return detailId > 0
|
||||
})
|
||||
|
||||
if success {
|
||||
fmt.Println("订单创建成功")
|
||||
} else {
|
||||
fmt.Println("订单创建失败:", database.LastErr.GetError())
|
||||
}
|
||||
|
||||
// 统计示例
|
||||
totalUsers := database.Count("user", common.Map{"status": 1})
|
||||
totalAmount := database.Sum("order", "amount", common.Map{"status": "paid"})
|
||||
|
||||
fmt.Printf("活跃用户数: %d, 总交易额: %.2f\n", totalUsers, totalAmount)
|
||||
}
|
||||
```
|
||||
| 关键字 | 功能 | 示例 |
|
||||
|--------|------|------|
|
||||
| `ORDER` / `order` | 排序 | `"ORDER": "id DESC"` |
|
||||
| `GROUP` / `group` | 分组 | `"GROUP": "dept_id"` |
|
||||
| `LIMIT` / `limit` | 限制 | `"LIMIT": 10` |
|
||||
| `OFFSET` / `offset` | 偏移 | `"OFFSET": 20` |
|
||||
| `HAVING` / `having` | 分组过滤 | `"HAVING": Map{"cnt[>]": 5}` |
|
||||
| `DISTINCT` / `distinct` | 去重 | 在 SELECT 中使用 |
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 如何处理事务中的错误?
|
||||
A1: 在`Action`函数中返回`false`即可触发回滚,所有操作都会被撤销。
|
||||
### Q1: 多条件查询需要用 AND 包装吗?
|
||||
A1: 不再需要!现在多条件会自动用 AND 连接。当然,使用 `AND` 包装仍然有效(向后兼容)。
|
||||
|
||||
### Q2: 缓存何时会被清除?
|
||||
A2: 执行`Insert`、`Update`、`Delete`操作时会自动清除对应表的缓存。
|
||||
### Q2: 如何处理事务中的错误?
|
||||
A2: 在 `Action` 函数中返回 `false` 即可触发回滚,所有操作都会被撤销。
|
||||
|
||||
### Q3: 如何执行复杂的原生SQL?
|
||||
A3: 使用`Query`方法执行查询,使用`Exec`方法执行更新操作。
|
||||
### Q3: 缓存何时会被清除?
|
||||
A3: 执行 `Insert`、`Update`、`Delete`、`Upsert`、`BatchInsert` 操作时会自动清除对应表的缓存。
|
||||
|
||||
### Q4: 主从分离如何工作?
|
||||
A4: 查询操作自动使用从库(如果配置了),增删改操作使用主库。
|
||||
### Q4: 如何执行复杂的原生SQL?
|
||||
A4: 使用 `Query` 方法执行查询,使用 `Exec` 方法执行更新操作。
|
||||
|
||||
### Q5: 如何处理NULL值?
|
||||
A5: 使用`nil`作为值,查询时使用`"field": nil`表示`IS NULL`。
|
||||
### Q5: 主从分离如何工作?
|
||||
A5: 查询操作自动使用从库(如果配置了),增删改操作使用主库。
|
||||
|
||||
### Q6: 如何处理NULL值?
|
||||
A6: 使用 `nil` 作为值,查询时使用 `"field": nil` 表示 `IS NULL`。
|
||||
|
||||
### Q7: PostgreSQL 和 MySQL 语法有区别吗?
|
||||
A7: 框架会自动处理差异(占位符、引号等),代码无需修改。
|
||||
|
||||
---
|
||||
|
||||
*文档版本: 1.0*
|
||||
*最后更新: 2024年*
|
||||
*文档版本: 2.0*
|
||||
*最后更新: 2026年1月*
|
||||
|
||||
> 本文档基于HoTimeDB源码分析生成,如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念,但根据Golang语言特性进行了适配和优化。
|
||||
> 本文档基于HoTimeDB源码分析生成,如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念,但根据Golang语言特性进行了适配和优化。
|
||||
|
||||
Reference in New Issue
Block a user