refactor(db): 重命名批量插入方法并更新文档

- 将 BatchInsert 方法重命名为 Inserts,以更好地反映其功能
- 更新示例代码和文档,确保使用新方法名
- 删除过时的文档文件,整合 HoTimeDB 使用说明和 API 参考
- 优化 README.md,增强框架特性和安装说明的清晰度
This commit is contained in:
hoteas 2026-01-22 20:32:29 +08:00
parent 29a3b6095d
commit cf64276ab1
9 changed files with 366 additions and 452 deletions

View File

@ -169,7 +169,7 @@ onCondition := that.GetProcessor().ProcessConditionString(v.(string))
query += " LEFT JOIN " + table + " ON " + onCondition + " " query += " LEFT JOIN " + table + " ON " + onCondition + " "
``` ```
**Insert/BatchInsert/Update/Delete** 同样修改表名和字段名处理。 **Insert/Inserts/Update/Delete** 同样修改表名和字段名处理。
### 第5步修改 WHERE 条件处理([db/where.go](db/where.go) ### 第5步修改 WHERE 条件处理([db/where.go](db/where.go)

208
README.md
View File

@ -2,75 +2,40 @@
**高性能 Go Web 服务框架** **高性能 Go Web 服务框架**
## 特性 一个"小而全"的 Go Web 框架,内置 ORM、三级缓存、Session 管理,让你专注于业务逻辑。
## 核心特性
- **高性能** - 单机 10万+ QPS支持百万级并发用户 - **高性能** - 单机 10万+ QPS支持百万级并发用户
- **多数据库支持** - MySQL、SQLite3支持主从分离 - **内置 ORM** - 类 Medoo 语法,链式查询,支持 MySQL/SQLite/PostgreSQL
- **三级缓存系统** - Memory > Redis > DB自动穿透与回填 - **三级缓存** - Memory > Redis > DB自动穿透与回填
- **Session管理** - 内置会话管理,支持多种存储后端 - **Session 管理** - 内置会话管理,支持多种存储后端
- **自动代码生成** - 根据数据库表自动生成 CRUD 接口 - **代码生成** - 根据数据库表自动生成 CRUD 接口
- **丰富工具类** - 上下文管理、类型转换、加密解密等 - **开箱即用** - 微信支付/公众号/小程序、阿里云、腾讯云等 SDK 内置
## 快速开始 ## 文档
### 安装 | 文档 | 说明 |
|------|------|
| [快速上手指南](docs/QUICKSTART.md) | 5 分钟入门,安装配置、路由、中间件、基础数据库操作 |
| [HoTimeDB 使用说明](docs/HoTimeDB_使用说明.md) | 完整数据库 ORM 教程 |
| [HoTimeDB API 参考](docs/HoTimeDB_API参考.md) | 数据库 API 速查手册 |
## 安装
```bash ```bash
go get code.hoteas.com/golang/hotime go get code.hoteas.com/golang/hotime
``` ```
### 最小示例 ## 性能
```go | 并发数 | QPS | 成功率 | 平均延迟 |
package main |--------|-----|--------|----------|
| 500 | 99,960 | 100% | 5.0ms |
| **1000** | **102,489** | **100%** | **9.7ms** |
| 2000 | 75,801 | 99.99% | 26.2ms |
import ( > 测试环境24 核 CPUWindows 10Go 1.19.3
. "code.hoteas.com/golang/hotime"
. "code.hoteas.com/golang/hotime/common"
)
func main() {
appIns := Init("config/config.json")
appIns.Run(Router{
"app": {
"test": {
"hello": func(that *Context) {
that.Display(0, Map{"message": "Hello World"})
},
},
},
})
}
```
访问: http://localhost:8081/app/test/hello
## 性能测试报告
### 测试环境
| 项目 | 配置 |
|------|------|
| CPU | 24 核心 |
| 系统 | Windows 10 |
| Go 版本 | 1.19.3 |
### 测试结果
| 并发数 | QPS | 成功率 | 平均延迟 | P99延迟 |
|--------|-----|--------|----------|---------|
| 500 | 99,960 | 100% | 5.0ms | 25.2ms |
| **1000** | **102,489** | **100%** | **9.7ms** | **56.8ms** |
| 2000 | 75,801 | 99.99% | 26.2ms | 127.7ms |
| 5000 | 12,611 | 99.95% | 391.4ms | 781.4ms |
### 性能总结
```
最高 QPS: 102,489 请求/秒
最佳并发数: 1,000
```
### 并发用户估算 ### 并发用户估算
@ -79,24 +44,9 @@ func main() {
| 高频交互 | 1次/秒 | ~10万 | | 高频交互 | 1次/秒 | ~10万 |
| 活跃用户 | 1次/5秒 | ~50万 | | 活跃用户 | 1次/5秒 | ~50万 |
| 普通浏览 | 1次/10秒 | ~100万 | | 普通浏览 | 1次/10秒 | ~100万 |
| 低频访问 | 1次/30秒 | ~300万 |
**生产环境建议**: 保留 30-50% 性能余量,安全并发用户数约 **50万 - 70万**
### 与主流框架性能对比
| 框架 | 典型QPS | 基础实现 | 性能评级 |
|------|---------|----------|----------|
| **HoTime** | **~100K** | net/http | 第一梯队 |
| Fiber | ~100K+ | fasthttp | 第一梯队 |
| Gin | ~60-80K | net/http | 第二梯队 |
| Echo | ~60-80K | net/http | 第二梯队 |
| Chi | ~50-60K | net/http | 第二梯队 |
## 框架对比 ## 框架对比
### 功能特性对比
| 特性 | HoTime | Gin | Echo | Fiber | | 特性 | HoTime | Gin | Echo | Fiber |
|------|--------|-----|------|-------| |------|--------|-----|------|-------|
| 性能 | 100K QPS | 70K QPS | 70K QPS | 100K QPS | | 性能 | 100K QPS | 70K QPS | 70K QPS | 100K QPS |
@ -105,117 +55,25 @@ func main() {
| Session | ✅ 内置 | ❌ 需插件 | ❌ 需插件 | ❌ 需插件 | | Session | ✅ 内置 | ❌ 需插件 | ❌ 需插件 | ❌ 需插件 |
| 代码生成 | ✅ | ❌ | ❌ | ❌ | | 代码生成 | ✅ | ❌ | ❌ | ❌ |
| 微信/支付集成 | ✅ 内置 | ❌ | ❌ | ❌ | | 微信/支付集成 | ✅ 内置 | ❌ | ❌ | ❌ |
| 路由灵活性 | 中等 | 优秀 | 优秀 | 优秀 |
| 社区生态 | 较小 | 庞大 | 较大 | 较大 |
### HoTime 优势 ## 适用场景
1. **开箱即用** - 内置 ORM + 缓存 + Session无需额外集成
2. **三级缓存** - Memory > Redis > DB自动穿透与回填
3. **开发效率高** - 链式查询语法简洁,内置微信/云服务SDK
4. **性能优异** - 100K QPS媲美最快的 Fiber 框架
### 适用场景
| 场景 | 推荐度 | 说明 | | 场景 | 推荐度 | 说明 |
|------|--------|------| |------|--------|------|
| 中小型后台系统 | ⭐⭐⭐⭐⭐ | 完美适配,开发效率最高 | | 中小型后台系统 | ⭐⭐⭐⭐⭐ | 完美适配,开发效率最高 |
| 微信小程序后端 | ⭐⭐⭐⭐⭐ | 内置微信SDK | | 微信小程序后端 | ⭐⭐⭐⭐⭐ | 内置微信 SDK |
| 快速原型开发 | ⭐⭐⭐⭐⭐ | 代码生成 + 全功能集成 | | 快速原型开发 | ⭐⭐⭐⭐⭐ | 代码生成 + 全功能集成 |
| 高并发API服务 | ⭐⭐⭐⭐ | 性能足够 | | 高并发 API 服务 | ⭐⭐⭐⭐ | 性能足够 |
| 大型微服务 | ⭐⭐⭐ | 建议用Gin/Echo | | 大型微服务 | ⭐⭐⭐ | 建议用 Gin/Echo |
### 总体评价
| 维度 | 评分 | 说明 |
|------|------|------|
| 性能 | 95分 | 第一梯队媲美Fiber |
| 功能集成 | 90分 | 远超主流框架 |
| 开发效率 | 85分 | 适合快速开发 |
| 生态/社区 | 50分 | 持续建设中 |
> **总结**: HoTime 是"小而全"的高性能框架,性能不输主流,集成度远超主流,适合独立开发者或小团队快速构建中小型项目。
---
## 数据库操作
### 基础 CRUD
```go
// 查询单条
user := that.Db.Get("user", "*", Map{"id": 1})
// 查询列表
users := that.Db.Select("user", "*", Map{"status": 1, "ORDER": "id DESC"})
// 插入数据
id := that.Db.Insert("user", Map{"name": "test", "age": 18})
// 更新数据
rows := that.Db.Update("user", Map{"name": "new"}, Map{"id": 1})
// 删除数据
rows := that.Db.Delete("user", Map{"id": 1})
```
### 链式查询
```go
users := that.Db.Table("user").
LeftJoin("order", "user.id=order.user_id").
And("status", 1).
Order("id DESC").
Page(1, 10).
Select("*")
```
### 条件语法
| 语法 | 说明 | 示例 |
|------|------|------|
| key | 等于 | "id": 1 |
| key[>] | 大于 | "age[>]": 18 |
| key[<] | 小于 | "age[<]": 60 |
| key[!] | 不等于 | "status[!]": 0 |
| key[~] | LIKE | "name[~]": "test" |
| key[<>] | BETWEEN | "age[<>]": Slice{18, 60} |
## 缓存系统
三级缓存: **Memory > Redis > Database**
```go
// 通用缓存
that.Cache("key", value) // 设置
data := that.Cache("key") // 获取
that.Cache("key", nil) // 删除
// Session 缓存
that.Session("user_id", 123) // 设置
userId := that.Session("user_id") // 获取
```
## 中间件
```go
appIns.SetConnectListener(func(that *Context) bool {
if that.Session("user_id").Data == nil {
that.Display(2, "请先登录")
return true // 终止请求
}
return false // 继续处理
})
```
## 扩展功能 ## 扩展功能
- **微信支付/公众号/小程序** - dri/wechat/ - 微信支付/公众号/小程序 - `dri/wechat/`
- **阿里云服务** - dri/aliyun/ - 阿里云服务 - `dri/aliyun/`
- **腾讯云服务** - dri/tencent/ - 腾讯云服务 - `dri/tencent/`
- **文件上传下载** - dri/upload/, dri/download/ - 文件上传下载 - `dri/upload/`, `dri/download/`
- **MongoDB** - dri/mongodb/ - MongoDB - `dri/mongodb/`
- **RSA加解密** - dri/rsa/ - RSA 加解密 - `dri/rsa/`
## License ## License

View File

@ -1,252 +0,0 @@
# HoTimeDB ORM 文档集合
这是HoTimeDB ORM框架的完整文档集合包含使用说明、API参考、示例代码和测试数据。
## ⚠️ 重要更新说明
**语法修正通知**经过对源码的深入分析发现HoTimeDB的条件查询语法有特定规则
- ✅ **单个条件**可以直接写在Map中
- ⚠️ **多个条件**:必须使用`AND``OR`包装
- 📝 所有文档和示例代码已按正确语法更新
## 📚 文档列表
### 1. [HoTimeDB_使用说明.md](./HoTimeDB_使用说明.md)
**完整使用说明书** - 详细的功能介绍和使用指南
- 🚀 快速开始
- ⚙️ 数据库配置
- 🔧 基本操作 (CRUD)
- 🔗 链式查询构建器
- 🔍 条件查询语法
- 🔄 JOIN操作
- 📄 分页查询
- 📊 聚合函数
- 🔐 事务处理
- 💾 缓存机制
- ⚡ 高级特性
### 2. [HoTimeDB_API参考.md](./HoTimeDB_API参考.md)
**快速API参考手册** - 开发时的速查手册
- 📖 基本方法
- 🔧 CRUD操作
- 📊 聚合函数
- 📄 分页查询
- 🔍 条件语法参考
- 🔗 JOIN语法
- 🔐 事务处理
- 🛠️ 工具方法
### 3. [示例代码文件](../examples/hotimedb_examples.go)
**完整示例代码集合** - 可运行的实际应用示例(语法已修正)
- 🏗️ 基本初始化和配置
- 📝 基本CRUD操作
- 🔗 链式查询操作
- 🤝 JOIN查询操作
- 🔍 条件查询语法
- 📄 分页查询
- 📊 聚合函数查询
- 🔐 事务处理
- 💾 缓存机制
- 🔧 原生SQL执行
- 🚨 错误处理和调试
- ⚡ 性能优化技巧
- 🎯 完整应用示例
### 4. [test_tables.sql](./test_tables.sql)
**测试数据库结构** - 快速搭建测试环境
- 🏗️ 完整的表结构定义
- 📊 测试数据插入
- 🔍 索引优化
- 👁️ 视图示例
- 🔧 存储过程示例
## 🎯 核心特性
### 🌟 主要优势
- **类Medoo语法**: 参考PHP Medoo设计语法简洁易懂
- **链式查询**: 支持流畅的链式查询构建器
- **条件丰富**: 支持丰富的条件查询语法
- **事务支持**: 完整的事务处理机制
- **缓存集成**: 内置查询结果缓存
- **读写分离**: 支持主从数据库配置
- **类型安全**: 基于Golang的强类型系统
### 🔧 支持的数据库
- ✅ MySQL
- ✅ SQLite
- ✅ 其他标准SQL数据库
## 🚀 快速开始
### 1. 安装依赖
```bash
go mod init your-project
go get github.com/go-sql-driver/mysql
go get github.com/sirupsen/logrus
```
### 2. 创建测试数据库
```bash
mysql -u root -p < test_tables.sql
```
### 3. 基本使用
```go
import (
"code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/common"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
// 初始化数据库
database := &db.HoTimeDB{
Prefix: "app_",
Mode: 2, // 开发模式
}
database.SetConnect(func() (master, slave *sql.DB) {
master, _ = sql.Open("mysql", "user:pass@tcp(localhost:3306)/dbname")
return master, master
})
// 链式查询链式语法支持单独Where然后用And添加条件
users := database.Table("user").
Where("status", 1). // 链式中可以单独Where
And("age[>]", 18). // 用And添加更多条件
Order("created_time DESC").
Limit(0, 10).
Select("id,name,email")
// 或者使用传统语法多个条件必须用AND包装
users2 := database.Select("user", "id,name,email", common.Map{
"AND": common.Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "created_time DESC",
"LIMIT": []int{0, 10},
})
```
## ⚠️ 重要语法规则
**条件查询语法规则:**
- ✅ **单个条件**可以直接写在Map中
- ✅ **多个条件**:必须使用`AND``OR`包装
- ✅ **特殊参数**`ORDER``GROUP``LIMIT`与条件同级
```go
// ✅ 正确:单个条件
Map{"status": 1}
// ✅ 正确多个条件用AND包装
Map{
"AND": Map{
"status": 1,
"age[>]": 18,
},
"ORDER": "id DESC",
}
// ❌ 错误多个条件不用AND包装
Map{
"status": 1,
"age[>]": 18, // 不支持!
}
```
## 📝 条件查询语法速查
| 语法 | SQL | 说明 |
|------|-----|------|
| `"field": value` | `field = ?` | 等于 |
| `"field[!]": value` | `field != ?` | 不等于 |
| `"field[>]": value` | `field > ?` | 大于 |
| `"field[>=]": value` | `field >= ?` | 大于等于 |
| `"field[<]": value` | `field < ?` | 小于 |
| `"field[<=]": value` | `field <= ?` | 小于等于 |
| `"field[~]": "keyword"` | `field LIKE '%keyword%'` | 包含 |
| `"field[<>]": [min, max]` | `field BETWEEN ? AND ?` | 区间内 |
| `"field": [v1, v2, v3]` | `field IN (?, ?, ?)` | 在集合中 |
| `"field": nil` | `field IS NULL` | 为空 |
| `"field[#]": "NOW()"` | `field = NOW()` | 直接SQL |
## 🔗 JOIN语法速查
| 语法 | SQL | 说明 |
|------|-----|------|
| `"[>]table"` | `LEFT JOIN` | 左连接 |
| `"[<]table"` | `RIGHT JOIN` | 右连接 |
| `"[><]table"` | `INNER JOIN` | 内连接 |
| `"[<>]table"` | `FULL JOIN` | 全连接 |
## 🛠️ 链式方法速查
```go
db.Table("table") // 指定表名
.Where(key, value) // WHERE条件
.And(key, value) // AND条件
.Or(map) // OR条件
.LeftJoin(table, on) // LEFT JOIN
.Order(fields...) // ORDER BY
.Group(fields...) // GROUP BY
.Limit(offset, limit) // LIMIT
.Page(page, pageSize) // 分页
.Select(fields...) // 查询
.Get(fields...) // 获取单条
.Count() // 计数
.Update(data) // 更新
.Delete() // 删除
```
## ⚡ 性能优化建议
### 🔍 查询优化
- 使用合适的索引字段作为查询条件
- IN查询会自动优化为BETWEEN连续数字
- 避免SELECT *,指定需要的字段
- 合理使用LIMIT限制结果集大小
### 💾 缓存使用
- 查询结果会自动缓存
- 增删改操作会自动清除缓存
- `cached`表不参与缓存
### 🔐 事务处理
- 批量操作使用事务提高性能
- 事务中避免长时间操作
- 合理设置事务隔离级别
## 🚨 注意事项
### 🔒 安全相关
- 使用参数化查询防止SQL注入
- `[#]`语法需要注意防止注入
- 敏感数据加密存储
### 🎯 最佳实践
- 开发时设置`Mode = 2`便于调试
- 生产环境设置`Mode = 0`
- 合理设置表前缀
- 定期检查慢查询日志
## 🤝 与PHP Medoo的差异
1. **类型系统**: 使用`common.Map``common.Slice`
2. **错误处理**: Golang风格的错误处理
3. **链式调用**: 提供更丰富的链式API
4. **缓存集成**: 内置缓存功能
5. **并发安全**: 需要注意并发使用
## 📞 技术支持
- 📧 查看源码:`hotimedb.go`
- 📖 参考文档:本目录下的各个文档文件
- 🔧 示例代码:运行`HoTimeDB_示例代码.go`中的示例
---
**HoTimeDB ORM框架 - 让数据库操作更简单!** 🎉
> 本文档基于HoTimeDB源码分析生成参考了PHP Medoo的设计理念并根据Golang语言特性进行了优化。

View File

@ -307,19 +307,19 @@ func (that *HoTimeDB) Insert(table string, data map[string]interface{}) int64 {
return id return id
} }
// BatchInsert 批量插入数据 // Inserts 批量插入数据
// table: 表名 // table: 表名
// dataList: 数据列表,每个元素是一个 Map // dataList: 数据列表,每个元素是一个 Map
// 返回受影响的行数 // 返回受影响的行数
// //
// 示例: // 示例:
// //
// affected := db.BatchInsert("user", []Map{ // affected := db.Inserts("user", []Map{
// {"name": "张三", "age": 25, "email": "zhang@example.com"}, // {"name": "张三", "age": 25, "email": "zhang@example.com"},
// {"name": "李四", "age": 30, "email": "li@example.com"}, // {"name": "李四", "age": 30, "email": "li@example.com"},
// {"name": "王五", "age": 28, "email": "wang@example.com"}, // {"name": "王五", "age": 28, "email": "wang@example.com"},
// }) // })
func (that *HoTimeDB) BatchInsert(table string, dataList []Map) int64 { func (that *HoTimeDB) Inserts(table string, dataList []Map) int64 {
if len(dataList) == 0 { if len(dataList) == 0 {
return 0 return 0
} }

View File

@ -98,17 +98,17 @@ id := database.Insert("table", dataMap)
// 返回新插入记录的ID // 返回新插入记录的ID
``` ```
### 批量插入 (BatchInsert) - 新增 ### 批量插入 (Inserts) - 新增
```go ```go
// 使用 []Map 格式,更直观简洁 // 使用 []Map 格式,更直观简洁
affected := database.BatchInsert("table", []Map{ affected := database.Inserts("table", []Map{
{"col1": "val1", "col2": "val2", "col3": "val3"}, {"col1": "val1", "col2": "val2", "col3": "val3"},
{"col1": "val4", "col2": "val5", "col3": "val6"}, {"col1": "val4", "col2": "val5", "col3": "val6"},
}) })
// 返回受影响的行数 // 返回受影响的行数
// 支持 [#] 标记直接 SQL // 支持 [#] 标记直接 SQL
affected := database.BatchInsert("log", []Map{ affected := database.Inserts("log", []Map{
{"user_id": 1, "created_time[#]": "NOW()"}, {"user_id": 1, "created_time[#]": "NOW()"},
{"user_id": 2, "created_time[#]": "NOW()"}, {"user_id": 2, "created_time[#]": "NOW()"},
}) })
@ -465,7 +465,7 @@ stats := database.Select("order",
### 批量操作 ### 批量操作
```go ```go
// 批量插入(使用 []Map 格式) // 批量插入(使用 []Map 格式)
affected := database.BatchInsert("user", []Map{ affected := database.Inserts("user", []Map{
{"name": "用户1", "email": "user1@example.com", "status": 1}, {"name": "用户1", "email": "user1@example.com", "status": 1},
{"name": "用户2", "email": "user2@example.com", "status": 1}, {"name": "用户2", "email": "user2@example.com", "status": 1},
{"name": "用户3", "email": "user3@example.com", "status": 1}, {"name": "用户3", "email": "user3@example.com", "status": 1},
@ -511,3 +511,6 @@ result := database.Table("order").
*快速参考版本: 2.0* *快速参考版本: 2.0*
*更新日期: 2026年1月* *更新日期: 2026年1月*
**详细说明:**
- [HoTimeDB 使用说明](HoTimeDB_使用说明.md) - 完整教程

View File

@ -12,7 +12,7 @@ HoTimeDB是一个基于Golang实现的轻量级ORM框架参考PHP Medoo设计
- [查询(Select)](#查询select) - [查询(Select)](#查询select)
- [获取单条记录(Get)](#获取单条记录get) - [获取单条记录(Get)](#获取单条记录get)
- [插入(Insert)](#插入insert) - [插入(Insert)](#插入insert)
- [批量插入(BatchInsert)](#批量插入batchinsert) - [批量插入(Inserts)](#批量插入Inserts)
- [更新(Update)](#更新update) - [更新(Update)](#更新update)
- [Upsert操作](#upsert操作) - [Upsert操作](#upsert操作)
- [删除(Delete)](#删除delete) - [删除(Delete)](#删除delete)
@ -223,11 +223,11 @@ id := database.Insert("user", common.Map{
fmt.Println("插入的用户ID:", id) fmt.Println("插入的用户ID:", id)
``` ```
### 批量插入(BatchInsert) ### 批量插入(Inserts)
```go ```go
// 批量插入多条记录(使用 []Map 格式,更直观) // 批量插入多条记录(使用 []Map 格式,更直观)
affected := database.BatchInsert("user", []common.Map{ affected := database.Inserts("user", []common.Map{
{"name": "张三", "email": "zhang@example.com", "age": 25}, {"name": "张三", "email": "zhang@example.com", "age": 25},
{"name": "李四", "email": "li@example.com", "age": 30}, {"name": "李四", "email": "li@example.com", "age": 30},
{"name": "王五", "email": "wang@example.com", "age": 28}, {"name": "王五", "email": "wang@example.com", "age": 28},
@ -237,7 +237,7 @@ affected := database.BatchInsert("user", []common.Map{
fmt.Printf("批量插入 %d 条记录\n", affected) fmt.Printf("批量插入 %d 条记录\n", affected)
// 支持 [#] 标记直接插入 SQL 表达式 // 支持 [#] 标记直接插入 SQL 表达式
affected := database.BatchInsert("log", []common.Map{ affected := database.Inserts("log", []common.Map{
{"user_id": 1, "action": "login", "created_time[#]": "NOW()"}, {"user_id": 1, "action": "login", "created_time[#]": "NOW()"},
{"user_id": 2, "action": "logout", "created_time[#]": "NOW()"}, {"user_id": 2, "action": "logout", "created_time[#]": "NOW()"},
}) })
@ -808,7 +808,7 @@ A1: 不再需要!现在多条件会自动用 AND 连接。当然,使用 `AND
A2: 在 `Action` 函数中返回 `false` 即可触发回滚,所有操作都会被撤销。 A2: 在 `Action` 函数中返回 `false` 即可触发回滚,所有操作都会被撤销。
### Q3: 缓存何时会被清除? ### Q3: 缓存何时会被清除?
A3: 执行 `Insert``Update``Delete``Upsert``BatchInsert` 操作时会自动清除对应表的缓存。 A3: 执行 `Insert``Update``Delete``Upsert``Inserts` 操作时会自动清除对应表的缓存。
### Q4: 如何执行复杂的原生SQL ### Q4: 如何执行复杂的原生SQL
A4: 使用 `Query` 方法执行查询,使用 `Exec` 方法执行更新操作。 A4: 使用 `Query` 方法执行查询,使用 `Exec` 方法执行更新操作。
@ -828,3 +828,6 @@ A7: 框架会自动处理差异(占位符、引号等),代码无需修改
*最后更新: 2026年1月* *最后更新: 2026年1月*
> 本文档基于HoTimeDB源码分析生成如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念但根据Golang语言特性进行了适配和优化。 > 本文档基于HoTimeDB源码分析生成如有疑问请参考源码实现。该ORM框架参考了PHP Medoo的设计理念但根据Golang语言特性进行了适配和优化。
**更多参考:**
- [HoTimeDB API 参考](HoTimeDB_API参考.md) - API 速查手册

302
docs/QUICKSTART.md Normal file
View File

@ -0,0 +1,302 @@
# HoTime 快速上手指南
5 分钟入门 HoTime 框架。
## 安装
```bash
go get code.hoteas.com/golang/hotime
```
## 最小示例
```go
package main
import (
. "code.hoteas.com/golang/hotime"
. "code.hoteas.com/golang/hotime/common"
)
func main() {
appIns := Init("config/config.json")
appIns.Run(Router{
"app": {
"test": {
"hello": func(that *Context) {
that.Display(0, Map{"message": "Hello World"})
},
},
},
})
}
```
访问: `http://localhost:8081/app/test/hello`
## 配置文件
创建 `config/config.json`:
```json
{
"port": "8081",
"mode": 2,
"sessionName": "HOTIME",
"tpt": "tpt",
"defFile": ["index.html", "index.htm"],
"db": {
"mysql": {
"host": "localhost",
"port": "3306",
"name": "your_database",
"user": "root",
"password": "your_password"
}
},
"cache": {
"memory": {
"db": true,
"session": true,
"timeout": 7200
}
}
}
```
| 配置项 | 说明 |
|--------|------|
| `port` | 服务端口 |
| `mode` | 0=生产, 1=测试, 2=开发(输出SQL) |
| `tpt` | 静态文件目录 |
| `db` | 数据库配置 |
| `cache` | 缓存配置 |
## 路由系统
HoTime 使用三层路由结构:`模块/控制器/方法`
```go
appIns.Run(Router{
"模块名": {
"控制器名": {
"方法名": func(that *Context) {
// 处理逻辑
},
},
},
})
```
### 获取请求参数
```go
// GET/POST 参数
name := that.Req.FormValue("name")
// JSON Body
that.Req.ParseForm()
data := that.Req.PostForm
// 获取路径参数
module := that.RouterPath[0] // 模块
controller := that.RouterPath[1] // 控制器
action := that.RouterPath[2] // 方法
```
### 响应数据
```go
// 标准 JSON 响应
that.Display(0, Map{"data": "value"}) // 成功 code=0
that.Display(1, "错误信息") // 失败 code=1
// 直接写入
that.Resp.Write([]byte("raw data"))
```
## 中间件
```go
// 全局中间件(请求拦截)
appIns.SetConnectListener(func(that *Context) bool {
// 检查登录状态
if that.Session("user_id").Data == nil {
that.Display(2, "请先登录")
return true // 返回 true 终止请求
}
return false // 返回 false 继续处理
})
```
## Session 与缓存
```go
// Session 操作
that.Session("user_id", 123) // 设置
userId := that.Session("user_id") // 获取
that.Session("user_id", nil) // 删除
// 通用缓存
that.Cache("key", "value") // 设置
data := that.Cache("key") // 获取
that.Cache("key", nil) // 删除
```
三级缓存自动运作:**Memory → Redis → Database**
## 数据库操作(简要)
### 基础 CRUD
```go
// 查询列表
users := that.Db.Select("user", "*", Map{"status": 1})
// 查询单条
user := that.Db.Get("user", "*", Map{"id": 1})
// 插入
id := that.Db.Insert("user", Map{"name": "test", "age": 18})
// 更新
rows := that.Db.Update("user", Map{"name": "new"}, Map{"id": 1})
// 删除
rows := that.Db.Delete("user", Map{"id": 1})
```
### 链式查询
```go
users := that.Db.Table("user").
LeftJoin("order", "user.id=order.user_id").
Where("status", 1).
And("age[>]", 18).
Order("id DESC").
Page(1, 10).
Select("*")
```
### 条件语法速查
| 语法 | 说明 | 示例 |
|------|------|------|
| `key` | 等于 | `"id": 1` |
| `key[>]` | 大于 | `"age[>]": 18` |
| `key[<]` | 小于 | `"age[<]": 60` |
| `key[>=]` | 大于等于 | `"age[>=]": 18` |
| `key[<=]` | 小于等于 | `"age[<=]": 60` |
| `key[!]` | 不等于 | `"status[!]": 0` |
| `key[~]` | LIKE | `"name[~]": "test"` |
| `key[<>]` | BETWEEN | `"age[<>]": Slice{18, 60}` |
| `key` | IN | `"id": Slice{1, 2, 3}` |
### 事务
```go
success := that.Db.Action(func(tx db.HoTimeDB) bool {
tx.Update("user", Map{"balance[#]": "balance - 100"}, Map{"id": 1})
tx.Insert("order", Map{"user_id": 1, "amount": 100})
return true // 返回 true 提交false 回滚
})
```
> **更多数据库操作**:参见 [HoTimeDB 使用说明](HoTimeDB_使用说明.md)
## 扩展功能
| 功能 | 路径 | 说明 |
|------|------|------|
| 微信支付/公众号/小程序 | `dri/wechat/` | 微信全套 SDK |
| 阿里云服务 | `dri/aliyun/` | 企业认证等 |
| 腾讯云服务 | `dri/tencent/` | 企业认证等 |
| 文件上传 | `dri/upload/` | 文件上传处理 |
| 文件下载 | `dri/download/` | 文件下载处理 |
| MongoDB | `dri/mongodb/` | MongoDB 驱动 |
| RSA 加解密 | `dri/rsa/` | RSA 加解密工具 |
## 完整示例
```go
package main
import (
. "code.hoteas.com/golang/hotime"
. "code.hoteas.com/golang/hotime/common"
)
func main() {
appIns := Init("config/config.json")
// 登录检查中间件
appIns.SetConnectListener(func(that *Context) bool {
// 放行登录接口
if that.RouterPath[2] == "login" {
return false
}
if that.Session("user_id").Data == nil {
that.Display(2, "请先登录")
return true
}
return false
})
appIns.Run(Router{
"api": {
"user": {
"login": func(that *Context) {
phone := that.Req.FormValue("phone")
password := that.Req.FormValue("password")
user := that.Db.Get("user", "*", Map{
"phone": phone,
"password": password,
})
if user == nil {
that.Display(1, "账号或密码错误")
return
}
that.Session("user_id", user.GetInt64("id"))
that.Display(0, Map{"user": user})
},
"info": func(that *Context) {
userId := that.Session("user_id").ToInt64()
user := that.Db.Get("user", "*", Map{"id": userId})
that.Display(0, Map{"user": user})
},
"list": func(that *Context) {
page := that.Req.FormValue("page")
if page == "" {
page = "1"
}
users := that.Db.Table("user").
Where("status", 1).
Order("id DESC").
Page(ObjToInt(page), 10).
Select("id,name,phone,created_at")
total := that.Db.Count("user", Map{"status": 1})
that.Display(0, Map{
"list": users,
"total": total,
})
},
},
},
})
}
```
---
**下一步**
- [HoTimeDB 使用说明](HoTimeDB_使用说明.md) - 完整数据库教程
- [HoTimeDB API 参考](HoTimeDB_API参考.md) - API 速查手册

View File

@ -44,7 +44,7 @@ func main() {
results["6_pagination"] = testPagination(that) results["6_pagination"] = testPagination(that)
// 7. 批量插入测试 // 7. 批量插入测试
results["7_batch_insert"] = testBatchInsert(that) results["7_batch_insert"] = testInserts(that)
// 8. Upsert 测试 // 8. Upsert 测试
results["8_upsert"] = testUpsert(that) results["8_upsert"] = testUpsert(that)
@ -86,7 +86,7 @@ func main() {
"join": func(that *Context) { that.Display(0, testJoinQuery(that)) }, "join": func(that *Context) { that.Display(0, testJoinQuery(that)) },
"aggregate": func(that *Context) { that.Display(0, testAggregate(that)) }, "aggregate": func(that *Context) { that.Display(0, testAggregate(that)) },
"pagination": func(that *Context) { that.Display(0, testPagination(that)) }, "pagination": func(that *Context) { that.Display(0, testPagination(that)) },
"batch": func(that *Context) { that.Display(0, testBatchInsert(that)) }, "batch": func(that *Context) { that.Display(0, testInserts(that)) },
"upsert": func(that *Context) { that.Display(0, testUpsert(that)) }, "upsert": func(that *Context) { that.Display(0, testUpsert(that)) },
"transaction": func(that *Context) { that.Display(0, testTransaction(that)) }, "transaction": func(that *Context) { that.Display(0, testTransaction(that)) },
"rawsql": func(that *Context) { that.Display(0, testRawSQL(that)) }, "rawsql": func(that *Context) { that.Display(0, testRawSQL(that)) },
@ -650,14 +650,14 @@ func testPagination(that *Context) Map {
} }
// ==================== 7. 批量插入测试 ==================== // ==================== 7. 批量插入测试 ====================
func testBatchInsert(that *Context) Map { func testInserts(that *Context) Map {
result := Map{"name": "批量插入测试", "tests": Slice{}} result := Map{"name": "批量插入测试", "tests": Slice{}}
tests := Slice{} tests := Slice{}
// 7.1 批量插入 // 7.1 批量插入
test1 := Map{"name": "BatchInsert 批量插入"} test1 := Map{"name": "Inserts 批量插入"}
timestamp := time.Now().UnixNano() timestamp := time.Now().UnixNano()
affected1 := that.Db.BatchInsert("test_batch", []Map{ affected1 := that.Db.Inserts("test_batch", []Map{
{"name": fmt.Sprintf("批量测试1_%d", timestamp), "title": "标题1", "state": 1}, {"name": fmt.Sprintf("批量测试1_%d", timestamp), "title": "标题1", "state": 1},
{"name": fmt.Sprintf("批量测试2_%d", timestamp), "title": "标题2", "state": 1}, {"name": fmt.Sprintf("批量测试2_%d", timestamp), "title": "标题2", "state": 1},
{"name": fmt.Sprintf("批量测试3_%d", timestamp), "title": "标题3", "state": 1}, {"name": fmt.Sprintf("批量测试3_%d", timestamp), "title": "标题3", "state": 1},
@ -668,9 +668,9 @@ func testBatchInsert(that *Context) Map {
tests = append(tests, test1) tests = append(tests, test1)
// 7.2 带 [#] 的批量插入 // 7.2 带 [#] 的批量插入
test2 := Map{"name": "BatchInsert 带 [#] 标记"} test2 := Map{"name": "Inserts 带 [#] 标记"}
timestamp2 := time.Now().UnixNano() timestamp2 := time.Now().UnixNano()
affected2 := that.Db.BatchInsert("test_batch", []Map{ affected2 := that.Db.Inserts("test_batch", []Map{
{"name": fmt.Sprintf("带时间测试1_%d", timestamp2), "title": "标题带时间1", "state": 1, "create_time[#]": "NOW()"}, {"name": fmt.Sprintf("带时间测试1_%d", timestamp2), "title": "标题带时间1", "state": 1, "create_time[#]": "NOW()"},
{"name": fmt.Sprintf("带时间测试2_%d", timestamp2), "title": "标题带时间2", "state": 1, "create_time[#]": "NOW()"}, {"name": fmt.Sprintf("带时间测试2_%d", timestamp2), "title": "标题带时间2", "state": 1, "create_time[#]": "NOW()"},
}) })

View File

@ -766,12 +766,12 @@ correctUsers4 := db.Select("user", "*", common.Map{
_ = db _ = db
} }
// BatchInsertExample 批量插入示例 // InsertsExample 批量插入示例
func BatchInsertExample(database *db.HoTimeDB) { func InsertsExample(database *db.HoTimeDB) {
fmt.Println("\n=== 批量插入示例 ===") fmt.Println("\n=== 批量插入示例 ===")
// 批量插入用户(使用 []Map 格式) // 批量插入用户(使用 []Map 格式)
affected := database.BatchInsert("user", []common.Map{ affected := database.Inserts("user", []common.Map{
{"name": "批量用户1", "email": "batch1@example.com", "age": 25, "status": 1}, {"name": "批量用户1", "email": "batch1@example.com", "age": 25, "status": 1},
{"name": "批量用户2", "email": "batch2@example.com", "age": 30, "status": 1}, {"name": "批量用户2", "email": "batch2@example.com", "age": 30, "status": 1},
{"name": "批量用户3", "email": "batch3@example.com", "age": 28, "status": 1}, {"name": "批量用户3", "email": "batch3@example.com", "age": 28, "status": 1},
@ -779,7 +779,7 @@ func BatchInsertExample(database *db.HoTimeDB) {
fmt.Printf("批量插入了 %d 条用户记录\n", affected) fmt.Printf("批量插入了 %d 条用户记录\n", affected)
// 批量插入日志(使用 [#] 标记直接 SQL // 批量插入日志(使用 [#] 标记直接 SQL
logAffected := database.BatchInsert("log", []common.Map{ logAffected := database.Inserts("log", []common.Map{
{"user_id": 1, "action": "login", "ip": "192.168.1.1", "created_time[#]": "NOW()"}, {"user_id": 1, "action": "login", "ip": "192.168.1.1", "created_time[#]": "NOW()"},
{"user_id": 2, "action": "logout", "ip": "192.168.1.2", "created_time[#]": "NOW()"}, {"user_id": 2, "action": "logout", "ip": "192.168.1.2", "created_time[#]": "NOW()"},
{"user_id": 3, "action": "view", "ip": "192.168.1.3", "created_time[#]": "NOW()"}, {"user_id": 3, "action": "view", "ip": "192.168.1.3", "created_time[#]": "NOW()"},
@ -838,7 +838,7 @@ func RunAllFixedExamples() {
fmt.Println("所有示例代码已修正完毕,语法正确!") fmt.Println("所有示例代码已修正完毕,语法正确!")
fmt.Println("") fmt.Println("")
fmt.Println("新增功能示例说明:") fmt.Println("新增功能示例说明:")
fmt.Println(" - BatchInsertExample(db): 批量插入示例,使用 []Map 格式") fmt.Println(" - InsertsExample(db): 批量插入示例,使用 []Map 格式")
fmt.Println(" - UpsertExample(db): 插入或更新示例") fmt.Println(" - UpsertExample(db): 插入或更新示例")
} }