Kratos 事务管理与循环依赖解决方案

介绍 Kratos 项目中的事务抽象方法,并通过接口解耦解决 data 与 biz 层之间的循环依赖。

Kratos 当中的数据流向是 server -> biz -> data

data 需要实现 biz 中定义的接口,利用注入的基础设施做 crud

但实际上我们需要在 biz层去开启事务的时候需要依赖于 data 层的 DB实例

如果在 data 层暴露一个 GetDB 的方法,看上去没什么问题,实际上会导致一个循环依赖的问题

对于这种情况,我们可以在 data 层去创建一个事务管理器,并在 biz 层去定义事务管理器需要实现的接口,这样抽离公共模块能保证代码的文件运行同时保证解耦。

代码相关实现

go
shortvid-service/internal/data/tx.go
package data

import (
	"shortvid-backend/app/shortvid-service/internal/biz"

	"github.com/go-kratos/kratos/v2/log"
	"gorm.io/gorm"
)

type txRepo struct {
	data *Data
}

func NewTxRepo(data *Data) biz.TxRepo {
	return &txRepo{
		data: data,
	}
}

func (r *txRepo) ExecFunc(fn func(tx *gorm.DB) error) error {
	err := r.data.db.Transaction(func(tx *gorm.DB) error {
		return fn(tx)
	})
	if err != nil {
		r.data.logger.Log(log.LevelError, "error", "transaction failed")
		return err
	}
	return nil
}

biz 层的接口

go
shortvid-service/internal/biz/tx.go
package biz

import "gorm.io/gorm"

// 事务聚合器
type TxRepo interface {
	ExecFunc(fn func(*gorm.DB) error) error
}

在真正用到事务的时候将TxRepo注入到 biz 的结构体当中

代码示例:

VS Code 中配置 Protobuf 开发环境
Kratos 服务注册与发现实践