890 lines
19 KiB
Markdown
890 lines
19 KiB
Markdown
# HoTimeDB ORM 使用说明书
|
||
|
||
## 概述
|
||
|
||
HoTimeDB是一个基于Golang实现的轻量级ORM框架,参考PHP Medoo设计,提供简洁的数据库操作接口。支持MySQL、SQLite等数据库,并集成了缓存、事务、链式查询等功能。
|
||
|
||
## 目录
|
||
|
||
- [快速开始](#快速开始)
|
||
- [数据库配置](#数据库配置)
|
||
- [基本操作](#基本操作)
|
||
- [查询(Select)](#查询select)
|
||
- [获取单条记录(Get)](#获取单条记录get)
|
||
- [插入(Insert)](#插入insert)
|
||
- [更新(Update)](#更新update)
|
||
- [删除(Delete)](#删除delete)
|
||
- [链式查询构建器](#链式查询构建器)
|
||
- [条件查询语法](#条件查询语法)
|
||
- [JOIN操作](#join操作)
|
||
- [分页查询](#分页查询)
|
||
- [聚合函数](#聚合函数)
|
||
- [事务处理](#事务处理)
|
||
- [缓存机制](#缓存机制)
|
||
- [高级特性](#高级特性)
|
||
|
||
## 快速开始
|
||
|
||
### 初始化数据库连接
|
||
|
||
```go
|
||
import (
|
||
"code.hoteas.com/golang/hotime/db"
|
||
"code.hoteas.com/golang/hotime/common"
|
||
"database/sql"
|
||
_ "github.com/go-sql-driver/mysql"
|
||
)
|
||
|
||
// 创建连接函数
|
||
func createConnection() (master, slave *sql.DB) {
|
||
master, _ = sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
|
||
// slave是可选的,用于读写分离
|
||
slave = master // 或者连接到从数据库
|
||
return
|
||
}
|
||
|
||
// 初始化HoTimeDB
|
||
db := &db.HoTimeDB{}
|
||
db.SetConnect(createConnection)
|
||
```
|
||
|
||
## 数据库配置
|
||
|
||
### 基本配置
|
||
|
||
```go
|
||
type HoTimeDB struct {
|
||
*sql.DB
|
||
ContextBase
|
||
DBName string
|
||
*cache.HoTimeCache
|
||
Log *logrus.Logger
|
||
Type string // 数据库类型
|
||
Prefix string // 表前缀
|
||
LastQuery string // 最后执行的SQL
|
||
LastData []interface{} // 最后的参数
|
||
ConnectFunc func(err ...*Error) (*sql.DB, *sql.DB)
|
||
LastErr *Error
|
||
limit Slice
|
||
*sql.Tx // 事务对象
|
||
SlaveDB *sql.DB // 从数据库
|
||
Mode int // 0生产模式,1测试模式,2开发模式
|
||
}
|
||
```
|
||
|
||
### 设置表前缀
|
||
|
||
```go
|
||
db.Prefix = "app_"
|
||
```
|
||
|
||
### 设置运行模式
|
||
|
||
```go
|
||
db.Mode = 2 // 开发模式,会输出SQL日志
|
||
```
|
||
|
||
## 基本操作
|
||
|
||
### 查询(Select)
|
||
|
||
#### 基本查询
|
||
|
||
```go
|
||
// 查询所有字段
|
||
users := db.Select("user")
|
||
|
||
// 查询指定字段
|
||
users := db.Select("user", "id,name,email")
|
||
|
||
// 查询指定字段(数组形式)
|
||
users := db.Select("user", []string{"id", "name", "email"})
|
||
|
||
// 单条件查询
|
||
users := db.Select("user", "*", common.Map{
|
||
"status": 1,
|
||
})
|
||
|
||
// 多条件查询(必须使用AND包装)
|
||
users = db.Select("user", "*", common.Map{
|
||
"AND": common.Map{
|
||
"status": 1,
|
||
"age[>]": 18,
|
||
},
|
||
})
|
||
```
|
||
|
||
#### 复杂条件查询
|
||
|
||
**重要说明:多个条件必须使用AND或OR包装,不能直接在根Map中写多个字段条件**
|
||
|
||
```go
|
||
// AND条件(多个条件必须用AND包装)
|
||
users := db.Select("user", "*", common.Map{
|
||
"AND": common.Map{
|
||
"status": 1,
|
||
"age[>]": 18,
|
||
"name[~]": "张",
|
||
},
|
||
})
|
||
|
||
// OR条件
|
||
users := db.Select("user", "*", common.Map{
|
||
"OR": common.Map{
|
||
"status": 1,
|
||
"type": 2,
|
||
},
|
||
})
|
||
|
||
// 混合条件(嵌套AND/OR)
|
||
users := db.Select("user", "*", common.Map{
|
||
"AND": common.Map{
|
||
"status": 1,
|
||
"OR": common.Map{
|
||
"age[<]": 30,
|
||
"level[>]": 5,
|
||
},
|
||
},
|
||
})
|
||
|
||
// 带ORDER BY、LIMIT等特殊条件
|
||
users := db.Select("user", "*", common.Map{
|
||
"AND": common.Map{
|
||
"status": 1,
|
||
"age[>]": 18,
|
||
},
|
||
"ORDER": "id DESC",
|
||
"LIMIT": 10,
|
||
})
|
||
|
||
// 带多个特殊条件
|
||
users := db.Select("user", "*", common.Map{
|
||
"OR": common.Map{
|
||
"level": "vip",
|
||
"balance[>]": 1000,
|
||
},
|
||
"ORDER": []string{"created_time DESC", "id ASC"},
|
||
"GROUP": "department",
|
||
"LIMIT": []int{0, 20}, // offset 0, limit 20
|
||
})
|
||
```
|
||
|
||
### 获取单条记录(Get)
|
||
|
||
```go
|
||
// 获取单个用户
|
||
user := db.Get("user", "*", common.Map{
|
||
"id": 1,
|
||
})
|
||
|
||
// 获取指定字段
|
||
user := db.Get("user", "id,name,email", common.Map{
|
||
"status": 1,
|
||
})
|
||
```
|
||
|
||
### 插入(Insert)
|
||
|
||
```go
|
||
// 基本插入
|
||
id := db.Insert("user", common.Map{
|
||
"name": "张三",
|
||
"email": "zhangsan@example.com",
|
||
"age": 25,
|
||
"status": 1,
|
||
"created_time[#]": "NOW()", // [#]表示直接插入SQL函数
|
||
})
|
||
|
||
// 返回插入的ID
|
||
fmt.Println("插入的用户ID:", id)
|
||
```
|
||
|
||
### 更新(Update)
|
||
|
||
```go
|
||
// 基本更新
|
||
affected := db.Update("user", common.Map{
|
||
"name": "李四",
|
||
"email": "lisi@example.com",
|
||
"updated_time[#]": "NOW()",
|
||
}, common.Map{
|
||
"id": 1,
|
||
})
|
||
|
||
// 条件更新
|
||
affected := db.Update("user", common.Map{
|
||
"status": 0,
|
||
}, common.Map{
|
||
"age[<]": 18,
|
||
"status": 1,
|
||
})
|
||
|
||
fmt.Println("更新的记录数:", affected)
|
||
```
|
||
|
||
### 删除(Delete)
|
||
|
||
```go
|
||
// 根据ID删除
|
||
affected := db.Delete("user", common.Map{
|
||
"id": 1,
|
||
})
|
||
|
||
// 条件删除
|
||
affected := db.Delete("user", common.Map{
|
||
"status": 0,
|
||
"created_time[<]": "2023-01-01",
|
||
})
|
||
|
||
fmt.Println("删除的记录数:", affected)
|
||
```
|
||
|
||
## 链式查询构建器
|
||
|
||
HoTimeDB提供了链式查询构建器,让查询更加直观:
|
||
|
||
```go
|
||
// 基本链式查询
|
||
users := db.Table("user").
|
||
Where("status", 1).
|
||
And("age[>]", 18).
|
||
Order("created_time DESC").
|
||
Limit(10, 20). // offset, limit
|
||
Select()
|
||
|
||
// 链式获取单条记录
|
||
user := db.Table("user").
|
||
Where("id", 1).
|
||
Get()
|
||
|
||
// 链式更新
|
||
affected := db.Table("user").
|
||
Where("id", 1).
|
||
Update(common.Map{
|
||
"name": "新名称",
|
||
"updated_time[#]": "NOW()",
|
||
})
|
||
|
||
// 链式删除
|
||
affected := db.Table("user").
|
||
Where("status", 0).
|
||
Delete()
|
||
|
||
// 链式统计
|
||
count := db.Table("user").
|
||
Where("status", 1).
|
||
Count()
|
||
```
|
||
|
||
### 链式条件组合
|
||
|
||
```go
|
||
// 复杂条件组合
|
||
users := db.Table("user").
|
||
Where("status", 1).
|
||
And("age[>=]", 18).
|
||
Or(common.Map{
|
||
"level[>]": 5,
|
||
"vip": 1,
|
||
}).
|
||
Order("created_time DESC", "id ASC").
|
||
Group("department").
|
||
Limit(0, 20).
|
||
Select("id,name,email,age")
|
||
```
|
||
|
||
## 条件查询语法
|
||
|
||
HoTimeDB支持丰富的条件查询语法,类似于Medoo:
|
||
|
||
### 基本比较
|
||
|
||
```go
|
||
// 等于
|
||
"id": 1
|
||
|
||
// 不等于
|
||
"id[!]": 1
|
||
|
||
// 大于
|
||
"age[>]": 18
|
||
|
||
// 大于等于
|
||
"age[>=]": 18
|
||
|
||
// 小于
|
||
"age[<]": 60
|
||
|
||
// 小于等于
|
||
"age[<=]": 60
|
||
```
|
||
|
||
### 模糊查询
|
||
|
||
```go
|
||
// LIKE %keyword%
|
||
"name[~]": "张"
|
||
|
||
// LIKE keyword% (右边任意)
|
||
"name[~!]": "张"
|
||
|
||
// LIKE %keyword (左边任意)
|
||
"name[!~]": "san"
|
||
|
||
// 手动LIKE(需要手动添加%)
|
||
"name[~~]": "%张%"
|
||
```
|
||
|
||
### 区间查询
|
||
|
||
```go
|
||
// BETWEEN
|
||
"age[<>]": []int{18, 60}
|
||
|
||
// NOT BETWEEN
|
||
"age[><]": []int{18, 25}
|
||
```
|
||
|
||
### IN查询
|
||
|
||
```go
|
||
// IN
|
||
"id": []int{1, 2, 3, 4, 5}
|
||
|
||
// NOT IN
|
||
"id[!]": []int{1, 2, 3}
|
||
```
|
||
|
||
### NULL查询
|
||
|
||
```go
|
||
// IS NULL
|
||
"deleted_at": nil
|
||
|
||
// IS NOT NULL
|
||
"deleted_at[!]": nil
|
||
```
|
||
|
||
### 直接SQL
|
||
|
||
```go
|
||
// 直接插入SQL表达式(注意防注入)
|
||
"created_time[#]": "> DATE_SUB(NOW(), INTERVAL 1 DAY)"
|
||
|
||
// 字段直接赋值(不使用参数化查询)
|
||
"update_time[#]": "NOW()"
|
||
|
||
// 直接SQL片段
|
||
"[##]": "user.status = 1 AND user.level > 0"
|
||
```
|
||
|
||
## JOIN操作
|
||
|
||
### 链式JOIN
|
||
|
||
```go
|
||
// LEFT JOIN
|
||
users := db.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").
|
||
RightJoin("order", "user.id = order.user_id").
|
||
Select()
|
||
|
||
// INNER JOIN
|
||
users := db.Table("user").
|
||
InnerJoin("profile", "user.id = profile.user_id").
|
||
Select()
|
||
|
||
// FULL JOIN
|
||
users := db.Table("user").
|
||
FullJoin("profile", "user.id = profile.user_id").
|
||
Select()
|
||
```
|
||
|
||
### 传统JOIN语法
|
||
|
||
```go
|
||
users := db.Select("user",
|
||
common.Slice{
|
||
common.Map{"[>]profile": "user.id = profile.user_id"},
|
||
common.Map{"[>]department": "user.dept_id = department.id"},
|
||
},
|
||
"user.*, profile.avatar, department.name AS dept_name",
|
||
common.Map{
|
||
"user.status": 1,
|
||
},
|
||
)
|
||
```
|
||
|
||
### JOIN类型说明
|
||
|
||
- `[>]`: LEFT JOIN
|
||
- `[<]`: RIGHT JOIN
|
||
- `[><]`: INNER JOIN
|
||
- `[<>]`: FULL JOIN
|
||
|
||
## 分页查询
|
||
|
||
### 基本分页
|
||
|
||
```go
|
||
// 设置分页:页码3,每页20条
|
||
users := db.Page(3, 20).PageSelect("user", "*", common.Map{
|
||
"status": 1,
|
||
})
|
||
|
||
// 链式分页
|
||
users := db.Table("user").
|
||
Where("status", 1).
|
||
Page(2, 15). // 第2页,每页15条
|
||
Select()
|
||
```
|
||
|
||
### 分页信息获取
|
||
|
||
```go
|
||
// 获取总数
|
||
total := db.Count("user", common.Map{
|
||
"status": 1,
|
||
})
|
||
|
||
// 计算分页信息
|
||
page := 2
|
||
pageSize := 20
|
||
offset := (page - 1) * pageSize
|
||
totalPages := (total + pageSize - 1) / pageSize
|
||
|
||
fmt.Printf("总记录数: %d, 总页数: %d, 当前页: %d\n", total, totalPages, page)
|
||
```
|
||
|
||
## 聚合函数
|
||
|
||
### 计数
|
||
|
||
```go
|
||
// 总数统计
|
||
total := db.Count("user")
|
||
|
||
// 条件统计
|
||
activeUsers := db.Count("user", common.Map{
|
||
"status": 1,
|
||
})
|
||
|
||
// JOIN统计
|
||
count := db.Count("user",
|
||
common.Slice{
|
||
common.Map{"[>]profile": "user.id = profile.user_id"},
|
||
},
|
||
common.Map{
|
||
"user.status": 1,
|
||
"profile.verified": 1,
|
||
},
|
||
)
|
||
```
|
||
|
||
### 求和
|
||
|
||
```go
|
||
// 基本求和
|
||
totalAmount := db.Sum("order", "amount")
|
||
|
||
// 条件求和
|
||
paidAmount := db.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
|
||
// 事务操作
|
||
success := db.Action(func(tx db.HoTimeDB) bool {
|
||
// 在事务中执行多个操作
|
||
|
||
// 扣减用户余额
|
||
affected1 := tx.Update("user", common.Map{
|
||
"balance[#]": "balance - 100",
|
||
}, common.Map{
|
||
"id": 1,
|
||
})
|
||
|
||
if affected1 == 0 {
|
||
return false // 回滚
|
||
}
|
||
|
||
// 创建订单
|
||
orderId := tx.Insert("order", common.Map{
|
||
"user_id": 1,
|
||
"amount": 100,
|
||
"status": "paid",
|
||
"created_time[#]": "NOW()",
|
||
})
|
||
|
||
if orderId == 0 {
|
||
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 // 提交
|
||
})
|
||
|
||
if success {
|
||
fmt.Println("事务执行成功")
|
||
} else {
|
||
fmt.Println("事务回滚")
|
||
fmt.Println("错误:", db.LastErr.GetError())
|
||
}
|
||
```
|
||
|
||
## 缓存机制
|
||
|
||
HoTimeDB集成了缓存功能,可以自动缓存查询结果:
|
||
|
||
### 缓存配置
|
||
|
||
```go
|
||
import "code.hoteas.com/golang/hotime/cache"
|
||
|
||
// 设置缓存
|
||
db.HoTimeCache = &cache.HoTimeCache{
|
||
// 缓存配置
|
||
}
|
||
```
|
||
|
||
### 缓存行为
|
||
|
||
- 查询操作会自动检查缓存
|
||
- 增删改操作会自动清除相关缓存
|
||
- 缓存键格式:`表名:查询MD5`
|
||
- `cached`表不会被缓存
|
||
|
||
### 缓存清理
|
||
|
||
```go
|
||
// 手动清除表缓存
|
||
db.HoTimeCache.Db("user*", nil) // 清除user表所有缓存
|
||
```
|
||
|
||
## 高级特性
|
||
|
||
### 调试模式
|
||
|
||
```go
|
||
// 设置调试模式
|
||
db.Mode = 2
|
||
|
||
// 查看最后执行的SQL
|
||
fmt.Println("最后的SQL:", db.LastQuery)
|
||
fmt.Println("参数:", db.LastData)
|
||
fmt.Println("错误:", db.LastErr.GetError())
|
||
```
|
||
|
||
### 主从分离
|
||
|
||
```go
|
||
func createConnection() (master, slave *sql.DB) {
|
||
// 主库连接
|
||
master, _ = sql.Open("mysql", "user:password@tcp(master:3306)/database")
|
||
|
||
// 从库连接
|
||
slave, _ = sql.Open("mysql", "user:password@tcp(slave:3306)/database")
|
||
|
||
return master, slave
|
||
}
|
||
|
||
db.SetConnect(createConnection)
|
||
// 查询会自动使用从库,增删改使用主库
|
||
```
|
||
|
||
### 原生SQL执行
|
||
|
||
```go
|
||
// 执行查询SQL
|
||
results := db.Query("SELECT * FROM user WHERE age > ? AND status = ?", 18, 1)
|
||
|
||
// 执行更新SQL
|
||
result, err := db.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
|
||
})
|
||
```
|
||
|
||
## 特殊语法详解
|
||
|
||
### 条件标记符说明
|
||
|
||
| 标记符 | 功能 | 示例 | 生成SQL |
|
||
|--------|------|------|---------|
|
||
| `[>]` | 大于 | `"age[>]": 18` | `age > 18` |
|
||
| `[<]` | 小于 | `"age[<]": 60` | `age < 60` |
|
||
| `[>=]` | 大于等于 | `"age[>=]": 18` | `age >= 18` |
|
||
| `[<=]` | 小于等于 | `"age[<=]": 60` | `age <= 60` |
|
||
| `[!]` | 不等于/NOT IN | `"id[!]": 1` | `id != 1` |
|
||
| `[~]` | LIKE模糊查询 | `"name[~]": "张"` | `name LIKE '%张%'` |
|
||
| `[!~]` | 左模糊 | `"name[!~]": "张"` | `name LIKE '%张'` |
|
||
| `[~!]` | 右模糊 | `"name[~!]": "张"` | `name LIKE '张%'` |
|
||
| `[~~]` | 手动LIKE | `"name[~~]": "%张%"` | `name LIKE '%张%'` |
|
||
| `[<>]` | BETWEEN | `"age[<>]": [18,60]` | `age BETWEEN 18 AND 60` |
|
||
| `[><]` | NOT BETWEEN | `"age[><]": [18,25]` | `age NOT BETWEEN 18 AND 25` |
|
||
| `[#]` | 直接SQL | `"time[#]": "NOW()"` | `time = NOW()` |
|
||
| `[##]` | SQL片段 | `"[##]": "a > b"` | `a > b` |
|
||
| `[#!]` | 不等于直接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)
|
||
}
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### Q1: 如何处理事务中的错误?
|
||
A1: 在`Action`函数中返回`false`即可触发回滚,所有操作都会被撤销。
|
||
|
||
### Q2: 缓存何时会被清除?
|
||
A2: 执行`Insert`、`Update`、`Delete`操作时会自动清除对应表的缓存。
|
||
|
||
### Q3: 如何执行复杂的原生SQL?
|
||
A3: 使用`Query`方法执行查询,使用`Exec`方法执行更新操作。
|
||
|
||
### Q4: 主从分离如何工作?
|
||
A4: 查询操作自动使用从库(如果配置了),增删改操作使用主库。
|
||
|
||
### Q5: 如何处理NULL值?
|
||
A5: 使用`nil`作为值,查询时使用`"field": nil`表示`IS NULL`。
|
||
|
||
---
|
||
|
||
*文档版本: 1.0*
|
||
*最后更新: 2024年*
|
||
|
||
> 本文档基于HoTimeDB源码分析生成,如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念,但根据Golang语言特性进行了适配和优化。 |