Kratos的Data层不内置ORM,需开发者自主选型集成;它仅封装依赖注入、连接管理与基础接口,将持久化方案和数据建模完全交由使用者决定。

Kratos 的 Data 层不内置 ORM,得自己选并集成
Kratos 本身不提供类似 GORM 或 Ent 的完整 ORM 功能,Data 层只负责封装依赖注入、连接管理与基础数据访问接口。它把“用什么持久化”和“怎么建模”完全交给你决定——这是设计上的主动取舍,不是缺失。所以你看到 data.go 里只有 NewData、Close 和几个空壳 Repo 接口,没任何 SQL 生成或结构体映射逻辑。
常见错误是直接照搬其他框架的“自动迁移+结构体标签映射”思路,结果发现 Kratos 模板里连 db.AutoMigrate 都没地方写。这不是 bug,是提示你:该选型了。
- 轻量场景(如配置、简单状态):用
entgo+ SQLite 或内存 map,初始化时加载一次即可 - 中高并发业务(用户、订单):推荐
gorm或原生database/sql+sqlc,后者类型安全更强、无运行时反射开销 - 强一致性事务需求:必须搭配
DTM使用,且所有数据库操作需包裹在dtmcli.TccGlobalTransaction或Saga流程中,不能靠单库事务兜底
SQLc + database/sql 是 Kratos 生态最稳的组合
官方示例和社区主流实践都倾向 sqlc:它从 SQL 文件生成类型安全的 Go 结构体和方法,和 Kratos 的接口驱动风格天然契合。你写好 query.sql,sqlc generate 出来的是纯 Go 代码,没有运行时 magic,调试链路清晰,IDE 支持好。
容易踩的坑是忽略 sqlc 的 schema 绑定方式——它不读数据库元信息,而是靠 SQL 中的 SELECT * 或显式字段列表推导结构体。一旦 SQL 写成 SELECT u.* FROM users u,生成的 struct 就会漏掉表别名带来的字段前缀,导致 scan 失败。
- 必须用显式字段:
SELECT id, name, created_at FROM users - 多表 JOIN 要加别名并统一前缀:
SELECT u.id, u.name, p.title FROM users u JOIN posts p ON u.id = p.user_id - 在 Kratos 的
data包里,把sqlc生成的Queries类型注入到Repo实现中,而非直接暴露Queries -
database/sql的DB实例应通过 Kratos 的registry注入,避免全局变量或硬编码sql.Open
事务边界必须严格落在 UseCase 层,不能藏在 Repo 里
Kratos 的分层约定很明确:Data 层只做单次 DB 操作,Biz 层协调逻辑,Service 层暴露 API。但很多人把事务控制写进 Repo.CreateUserTx 这类方法,结果导致 UseCase 无法组合多个 Repo 调用并共享同一事务——因为每个 Repo 自己开了新 tx,互相隔离。
正确做法是把 *sql.Tx 当作参数透传:Repo 方法签名带 ctx context.Context, tx *sql.Tx,UseCase 层统一 db.Begin(),再把 tx 传给各 Repo 方法。Kratos 的 transactor 工具包(非内置,需自行引入)可简化这个流程,但核心逻辑不变。
- Repo 方法不应调用
tx.Commit()或tx.Rollback(),那是 UseCase 的职责 - 如果用了
gorm,务必禁用其默认事务模式:gorm.Config{SkipDefaultTransaction: true} - 涉及跨库操作(如 Kratos 用户库 + Crux 业务库),必须用
DTM协调,不能依赖本地sql.Tx
连接池配置不调优,高并发下秒变超时黑洞
Kratos 默认用 database/sql,但模板里常只配了 db.SetMaxOpenConns(10)。这在本地测试没问题,一上生产,QPS 上 200 就开始大量 context deadline exceeded 报错——不是慢,是连接被占满后新请求直接等不到连接。
PostgreSQL 官方建议最大连接数 ≤ 服务器 CPU 核数 × 4,而 Kratos 服务实例通常跑在容器里,CPU limit 是 1 或 2。所以你要根据实际部署资源反推,而不是抄文档里的 “100”。
- 设
db.SetMaxOpenConns(20)(2C 容器常见值),db.SetMaxIdleConns(10),db.SetConnMaxLifetime(1h) - 用
pg_stat_activity查看真实连接占用,确认是否真被耗尽,还是有长事务阻塞 - Kratos 的
healthz接口可集成 DB 连接检测,但需手动在data包里加ping逻辑,模板不自带
真正麻烦的从来不是“怎么连上数据库”,而是“怎么让每次查询都在预期时间内拿到结果,且不拖垮整个服务”。Kratos 把自由给了你,也把责任一起交了过来——比如 sqlc 生成的代码要不要加 context.WithTimeout,Repo 方法要不要对空结果返回自定义 error 而不是 sql.ErrNoRows,这些细节堆起来,才是数据层稳不稳的关键。











