📋 前置要求
- Go 1.19 或更高版本
- 支持的数据库之一 (MySQL, PostgreSQL, SQLite)
🚀 第1步:安装TORM
# 创建新项目
mkdir my-torm-app
cd my-torm-app
go mod init my-torm-app
# 安装TORM
go get github.com/zhoudm1743/torm
🔧 第2步:创建现代化示例
创建模型文件 models/user.go
package models
import (
"time"
"github.com/zhoudm1743/torm/pkg/model"
)
// User 默认主键模型
type User struct {
model.BaseModel
ID interface{} `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
Age int `json:"age" db:"age"`
Status string `json:"status" db:"status"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// UserWithUUID 使用UUID作为主键的用户模型
type UserWithUUID struct {
model.BaseModel
UUID string `json:"uuid" db:"uuid" primary:"true"` // 自定义UUID主键
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// UserWithCompositePK 使用复合主键的用户模型
type UserWithCompositePK struct {
model.BaseModel
TenantID string `json:"tenant_id" db:"tenant_id" primary:"true"` // 复合主键1
UserID string `json:"user_id" db:"user_id" primary:"true"` // 复合主键2
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// NewUser 创建用户模型
func NewUser() *User {
user := &User{
BaseModel: *model.NewBaseModel(),
}
user.SetTable("users")
user.SetConnection("default")
return user
}
// NewUserWithUUID 创建UUID主键的用户模型
func NewUserWithUUID() *UserWithUUID {
user := &UserWithUUID{
BaseModel: *model.NewBaseModel(),
}
user.SetTable("users_uuid")
user.SetConnection("default")
// 自动检测主键标签
user.DetectPrimaryKeysFromStruct(user)
return user
}
// NewUserWithCompositePK 创建复合主键的用户模型
func NewUserWithCompositePK() *UserWithCompositePK {
user := &UserWithCompositePK{
BaseModel: *model.NewBaseModel(),
}
user.SetTable("users_composite")
user.SetConnection("default")
// 自动检测主键标签
user.DetectPrimaryKeysFromStruct(user)
return user
}
创建主文件 main.go
package main
import (
"examples/models"
"log"
"github.com/zhoudm1743/torm/pkg/db"
)
func main() {
// 配置数据库连接
conf := &db.Config{
Driver: "mysql",
Host: "localhost",
Port: 3306,
Username: "root",
Password: "123456",
Database: "orm",
}
err := db.AddConnection("default", conf)
if err != nil {
log.Fatal(err)
}
// ===== 查询构建器演示 =====
log.Println("===== 查询构建器演示 =====")
// 基础查询
query, err := db.Table("users", "default")
if err == nil {
// 查询所有用户
users, err := query.Select("id", "name", "email", "age").
Where("status", "=", "active").
OrderBy("created_at", "desc").
Limit(5).
Get()
if err == nil {
log.Printf("查询到 %d 个活跃用户", len(users))
}
// 条件查询
adults, err := query.Where("age", ">=", 18).
Where("status", "=", "active").
Count()
if err == nil {
log.Printf("成年活跃用户数量: %d", adults)
}
}
// ===== First和Find新功能演示 =====
log.Println("===== First和Find新功能演示 =====")
// First方法 - 只填充当前模型
user1 := models.NewUser()
_, err = user1.Where("id", "=", 1).First()
if err != nil {
log.Printf("查询失败: %v", err)
} else {
log.Printf("First结果: Name=%s, Age=%d", user1.Name, user1.Age)
}
// First方法 - 同时填充传入的指针
user2 := models.NewUser()
var anotherUser models.User
_, err = user2.Where("id", "=", 2).First(&anotherUser)
if err != nil {
log.Printf("查询失败: %v", err)
} else {
log.Printf("First + 指针填充: 当前=%s, 指针=%s", user2.Name, anotherUser.Name)
}
// Find方法 - 同时填充传入的指针
user3 := models.NewUser()
var targetUser models.User
_, err = user3.Find(1, &targetUser)
if err != nil {
log.Printf("Find失败: %v", err)
} else {
log.Printf("Find + 指针填充: 当前=%s, 指针=%s", user3.Name, targetUser.Name)
}
// ===== db包First和Find方法演示 =====
log.Println("===== db包First和Find方法演示 =====")
// db.Table().First()
query1, err := db.Table("users", "default")
if err == nil {
dbResult1, err := query1.Where("id", "=", 1).First()
if err == nil {
log.Printf("db.First() 结果: %s", dbResult1["name"])
}
}
// db.Table().First(&model)
query2, err := db.Table("users", "default")
if err == nil {
var userStruct models.User
_, err := query2.Where("id", "=", 1).First(&userStruct)
if err == nil {
log.Printf("db.First(&model) 结果: Name=%s", userStruct.Name)
}
}
// ===== 自定义主键功能演示 =====
log.Println("===== 自定义主键功能演示 =====")
// 默认主键
user4 := models.NewUser()
log.Printf("默认主键: %v", user4.PrimaryKeys())
// UUID主键
userUUID := models.NewUserWithUUID()
userUUID.UUID = "550e8400-e29b-41d4-a716-446655440000"
userUUID.SetAttribute("uuid", userUUID.UUID)
log.Printf("UUID主键: %v, 值: %v", userUUID.PrimaryKeys(), userUUID.GetKey())
// 复合主键
userComposite := models.NewUserWithCompositePK()
userComposite.SetAttribute("tenant_id", "tenant-001")
userComposite.SetAttribute("user_id", "user-001")
log.Printf("复合主键: %v, 值: %v", userComposite.PrimaryKeys(), userComposite.GetKey())
// 手动设置主键
user5 := models.NewUser()
user5.SetPrimaryKeys([]string{"tenant_id", "user_code"})
log.Printf("手动设置复合主键: %v", user5.PrimaryKeys())
// ===== 高级查询功能演示 =====
log.Println("===== 高级查询功能演示 =====")
// 复杂条件查询
complexQuery, err := db.Table("users", "default")
if err == nil {
result, err := complexQuery.
Select("id", "name", "email").
Where("age", "BETWEEN", []interface{}{20, 40}).
WhereIn("status", []interface{}{"active", "pending"}).
OrderBy("age", "ASC").
OrderBy("name", "DESC").
Limit(10).
Get()
if err == nil {
log.Printf("复杂查询结果数量: %d", len(result))
}
}
// 聚合查询
aggregateQuery, err := db.Table("users", "default")
if err == nil {
count, err := aggregateQuery.Where("status", "=", "active").Count()
if err == nil {
log.Printf("活跃用户总数: %d", count)
}
}
log.Println("===== 演示完成 =====")
}
🎯 第3步:运行代码
go run main.go
你将看到类似输出:
===== 查询构建器演示 =====
查询到 4 个活跃用户
成年活跃用户数量: 4
===== First和Find新功能演示 =====
First结果: Name=关联测试用户, Age=30
First + 指针填充: 当前=关联测试用户, 指针=关联测试用户
Find + 指针填充: 当前=关联测试用户, 指针=关联测试用户
===== db包First和Find方法演示 =====
db.First() 结果: 关联测试用户
db.First(&model) 结果: Name=关联测试用户
===== 自定义主键功能演示 =====
默认主键: [id]
UUID主键: [uuid], 值: 550e8400-e29b-41d4-a716-446655440000
复合主键: [tenant_id user_id], 值: map[tenant_id:tenant-001 user_id:user-001]
手动设置复合主键: [tenant_id user_code]
===== 高级查询功能演示 =====
复杂查询结果数量: 4
活跃用户总数: 4
===== 演示完成 =====
✨ 核心特性展示
1. 🚫 无Context依赖
// ❌ 旧方式 - 需要传递context
users, err := query.Get(ctx)
// ✅ 新方式 - 简洁的API
users, err := query.Get()
// 需要超时控制时可选使用
users, err := query.WithTimeout(5*time.Second).Get()
2. 🔗 链式查询构建器
// 直观的链式调用
results, err := db.Table("users").
Select("name", "email", "age").
Where("status", "=", "active").
Where("age", ">=", 18).
OrderBy("created_at", "desc").
Limit(10).
Get()
3. 🏗️ 现代化迁移系统
// 结构化的迁移定义
migrator.RegisterFunc("20240101_000001", "创建用户表",
func(conn db.ConnectionInterface) error {
// 迁移up逻辑
},
func(conn db.ConnectionInterface) error {
// 迁移down逻辑
})
4. 📊 智能模型层
// 自动处理CRUD操作
user := NewUser()
user.Name = "新用户"
user.Save() // 自动决定INSERT或UPDATE
📚 下一步
现在你已经掌握了TORM的基础用法!接下来可以探索:
💡 关键改进
TORM 现在提供:
- ✅ 可选的超时控制 (
WithTimeout(),WithContext()) - ✅ 完整的查询构建器
- ✅ 自动事务管理
- ✅ 类型安全的模型操作
- ✅ 现代化的迁移系统
享受现代化的Go ORM体验! 🚀
📈 API 重构说明
从 Context-Based 到 Context-Free
在最新版本中,TORM 进行了重大重构,移除了强制的 context.Context 参数,让API更加简洁易用:
❌ 旧版API(需要传递context)
// 旧方式 - 每个调用都需要context
ctx := context.Background()
// 查询操作
users, err := query.Get(ctx)
user, err := query.First(ctx)
// 数据库操作
result, err := conn.Exec(ctx, "INSERT INTO ...", args...)
rows, err := conn.Query(ctx, "SELECT ...", args...)
// 模型操作
err = user.Save(ctx)
err = user.Find(ctx, id)
err = user.Delete(ctx)
// 事务操作
tx, err := conn.Begin(ctx)
✅ 新版API(context-free)
// 新方式 - 简洁的API,无需context
// 查询操作
users, err := query.Get()
user, err := query.First()
// 数据库操作
result, err := conn.Exec("INSERT INTO ...", args...)
rows, err := conn.Query("SELECT ...", args...)
// 模型操作
err = user.Save()
err = user.Find(id)
err = user.Delete()
// 事务操作
err = db.Transaction(func(tx db.TransactionInterface) error {
// 事务逻辑
return nil
})
🎛️ 可选的Context控制
当需要超时控制或取消操作时,可以使用新增的方法:
// 超时控制
users, err := query.WithTimeout(5*time.Second).Get()
// 自定义context
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
users, err := query.WithContext(ctx).Get()
🔄 迁移指南
如果你正在从旧版本升级,请按以下步骤迁移:
-
移除显式的context参数:
// 旧代码 users, err := db.Table("users").Get(ctx) // 新代码 users, err := db.Table("users").Get() -
使用新的事务API:
// 旧代码 tx, err := conn.Begin(ctx) if err != nil { return err } defer tx.Rollback() _, err = tx.Exec("INSERT INTO ...", args...) if err != nil { return err } return tx.Commit() // 新代码 err := db.Transaction(func(tx db.TransactionInterface) error { _, err := tx.Exec("INSERT INTO ...", args...) return err // 自动处理commit/rollback }) -
在需要时添加超时控制:
// 长时间运行的查询 results, err := db.Table("large_table"). WithTimeout(30*time.Second). Get()