接入数据库
演示 Cherry 接入 MySQL 的最小完整流程,涵盖三件事:
- 注册并使用 gorm 组件 连接数据库
- 从节点的私有配置
__settings__读取参数 - 在 Actor 里挂定时器,周期性执行逻辑
这个示例是 Standalone(单节点)模式,不需要 NATS。
要求
- Go >= 1.24
- MySQL
准备数据库
示例目录下提供了建表脚本 demo_gorm/db.sql,先导入:
bash
cd demo_gorm
mysql -uroot -p < db.sql脚本会创建 dev_center 库和 user_bind 表,并插入 2 条测试数据。
然后创建示例使用的账号(或改用你自己的账号):
sql
CREATE USER IF NOT EXISTS 'dev_user'@'%' IDENTIFIED BY 'dev_password';
GRANT ALL PRIVILEGES ON dev_center.* TO 'dev_user'@'%';
FLUSH PRIVILEGES;账号密码要匹配配置
账号必须和 config/demo-gorm.json 里 db 段的 user_name / password 一致,否则连不上。授权范围也要覆盖 db_name,只授权了别的库同样会被拒绝。
启动
bash
cd demo_gorm
go run .同样的规则:配置路径 ../config/demo-gorm.json 是相对工作目录的,必须在 demo_gorm 目录下启动。
代码结构
demo_gorm/
├── main.go 入口:注册 gorm 组件与 Actor
├── actor_gorm.go 业务 Actor:取连接、挂定时器、查库
├── user_bind_table.go 表结构定义
└── db.sql 建表脚本入口
go
func main() {
app := cherry.Configure(
"../config/demo-gorm.json", // 配置路径
"game-1", // nodeID 必须是配置里存在的节点
false, // 不接收客户端连接
cherry.Standalone, // 单节点模式
)
// 注册 gorm 组件,引擎启动时自动按配置连好所有数据库
app.Register(cherryGORM.NewComponent())
app.AddActors(&ActorDB{})
app.Startup()
}业务 Actor
go
type ActorDB struct {
cactor.Base
centerDB *gorm.DB
}
func (p *ActorDB) AliasID() string {
return "db" // Actor 路径:game-1.db
}
func (p *ActorDB) OnInit() {
// 1. 取组件
gormComponent, ok := p.App().Find(cherryGORM.Name).(*cherryGORM.Component)
if !ok || gormComponent == nil {
clog.Panicf("[component = %s] not found.", cherryGORM.Name)
}
// 2. 从节点私有配置读逻辑库 id
centerDbID := p.App().Settings().GetConfig("db_id_list").GetString("center_db_id")
// 3. 换取 *gorm.DB 并缓存到字段
p.centerDB = gormComponent.GetDb(centerDbID)
if p.centerDB == nil {
clog.Panic("center_db_1 not found")
}
// 挂定时器:每 5 秒查一次,1 秒后先跑一次
p.Timer().Add(5*time.Second, p.selectDB)
p.Timer().AddOnce(1*time.Second, p.selectPagination)
}Actor 里缓存 DB 连接
GetDb 返回的是一个连接池句柄,在 OnInit 里取一次缓存到字段即可,不用每次查询都重新取。Actor 内部字段只被自己的 goroutine 访问,也不需要加锁。
配置链路
数据库配置分布在三个地方,缺一不可:
json
{
"node": {
"game": [
{
"node_id": "game-1",
"__settings__": {
"db_id_list": {
"center_db_id": "center_db_1" // ③ 节点要用哪个逻辑库
}
}
}
]
},
"db": {
"center_db_group": [
{
"enable": true,
"db_id": "center_db_1", // ② 逻辑 id,与上面匹配
"db_name": "dev_center",
"host": "127.0.0.1",
"user_name": "dev_user",
"password": "dev_password",
"max_idle_connect": 4,
"max_open_connect": 8,
"log_mode": true
}
]
}
}app.Register(cherryGORM.NewComponent())— 注册组件db.center_db_group[0].db_id— 定义逻辑库 id 与连接信息node.game[].__settings__.db_id_list.center_db_id— 声明本节点要用哪个库
链路是:节点 → db_id_list 的值 → 匹配 db 段里的 db_id。任何一环对不上,GetDb 都会返回 nil。
表定义
go
type UserBindTable struct {
Id int64 `gorm:"primaryKey;column:id"`
Uid int64 `gorm:"column:uid"`
Pid string `gorm:"column:pid"`
BindTime int64 `gorm:"column:bind_time"`
}
// 显式指定表名,避免依赖 gorm 的复数命名规则
func (UserBindTable) TableName() string {
return "user_bind"
}分页查询
selectPagination 演示了 Count + Limit + Offset 的用法:
go
var total int64
p.centerDB.Model(&UserBindTable{}).Count(&total)
var list []UserBindTable
p.centerDB.Limit(10).Offset(0).Find(&list)
clog.Infof("total = %d, list = %v", total, list)期望输出
启动后应该看到:
[dbGroup =center_db_group, dbName = center_db_1] is connected.
count = 2
&{UID:1 SdkId:1 PID:1 OpenId:1 BindTime:0}
&{UID:2 SdkId:2 PID:2 OpenId:2 BindTime:0}
&{UID:1 SdkId:1 PID:1 OpenId:1 BindTime:0} <- 每 5 秒重复一次| 输出 | 说明 |
|---|---|
is connected | gorm 组件按配置连上了库 |
count = 2 | 分页查询拿到的总条数,与 db.sql 的测试数据一致 |
| 后面几行 | Timer().Add(5*time.Second, ...) 的循环查询 |
排查
| 报错 | 原因 |
|---|---|
center_db_1 not found | __settings__.db_id_list.center_db_id 的值在 db 段里找不到同名的 db_id |
Error 1045: Access denied | 账号密码不对,或被授权的库与 db_name 不一致 |
Table 'dev_center.user_bind' doesn't exist | db.sql 没导入,或导入到了别的库 |
| 没有任何日志输出 | db_id_list 缺失——组件只会打一条 warning 然后跳过初始化 |
文件说明
| 文件 | 内容 |
|---|---|
main.go | 入口:注册组件、注册 Actor、启动 |
actor_gorm.go | 业务 Actor:取 DB 句柄、挂定时器、执行查询 |
user_bind_table.go | gorm 模型结构体,对应 user_bind 表 |
db.sql | 建库建表脚本 |
安装 gorm 组件
components 仓库的模块路径已经变更,注意不要用旧路径:
bash
go get github.com/cherry-game/components/gorm@latestgo
import cherryGORM "github.com/cherry-game/components/gorm"下一步
- 组件详细配置与 API:gorm 组件
- Actor 定时器说明:Actor 模型 - 定时器
- 完整的配表读取:data-config 组件
- 从旧版本升级:版本迁移指南