Skip to content

接入数据库 ​

演示 Cherry 接入 MySQL 的最小完整流程,涵盖三件事:

  1. 注册并使用 gorm 组件 连接数据库
  2. 从节点的私有配置 __settings__ 读取参数
  3. 在 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
            }
        ]
    }
}
  1. app.Register(cherryGORM.NewComponent()) — 注册组件
  2. db.center_db_group[0].db_id — 定义逻辑库 id 与连接信息
  3. 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 connectedgorm 组件按配置连上了库
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 existdb.sql 没导入,或导入到了别的库
没有任何日志输出db_id_list 缺失——组件只会打一条 warning 然后跳过初始化

文件说明 ​

文件内容
main.go入口:注册组件、注册 Actor、启动
actor_gorm.go业务 Actor:取 DB 句柄、挂定时器、执行查询
user_bind_table.gogorm 模型结构体,对应 user_bind 表
db.sql建库建表脚本

安装 gorm 组件 ​

components 仓库的模块路径已经变更,注意不要用旧路径:

bash
go get github.com/cherry-game/components/gorm@latest
go
import cherryGORM "github.com/cherry-game/components/gorm"

下一步 ​