这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
在深入理解RDBMS的课程中,我们学习到了事务的一些特性。在简易tiktok的项目开发中,也需要开启事务保证数据库的一致性。接下来,我们将在go-zero框架下进行事务操作。
链接:深入理解RDBMS | 青训营笔记 - 掘金 (juejin.cn)
首先,在model_gen.go文件中注册事务上下文,TransCtx 暴露给logic开启事务:
func (m *defaultVideoModel) TransCtx(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.conn.TransactCtx(ctx, func(ctx context.Context, s sqlx.Session) error {
return fn(ctx, s)
})
}
接着注册定制的底层数据库操作功能:
1、插入数据
func (m *defaultVideoModel) TransInsert(ctx context.Context, session sqlx.Session, data *Video) (sql.Result, error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, videoRowsExpectAutoSet)
return session.ExecCtx(ctx, query, data.UserId, data.PlayUrl, data.CoverUrl, data.FavoriteCount, data.CommentCount, data.Title)
}
2、更新点赞表
func (m *defaultVideoModel) TransUpdateFavorite(ctx context.Context, session sqlx.Session, videoId int64) (sql.Result, error) {
query := fmt.Sprintf("update %s set `favorite_count`=`favorite_count`+1 where `video_id` = ?", m.table)
return session.ExecCtx(ctx, query, videoId)
}
点赞、评论、关注等操作都需要开启事务进行处理,先插入对应表,再更新user表、video表的状态,保持数据的一致性。
在go-zero中逻辑处理开启事务,req.Action_type == 1时,插入Favorite表并更新Video点赞数 :
if err := l.svcCtx.FavoriteModel.TransCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
newFavorite := model.Favorite{
VideoId: req.Video_id,
UserId: user_id,
}
_, err := l.svcCtx.FavoriteModel.TransInsert(ctx, session, &newFavorite)
if err != nil {
return err
}
if _, err := l.svcCtx.VideoModel.TransUpdateFavorite(ctx, session, req.Video_id); err != nil {
return err
}
return nil
}); err != nil {
return &types.Douyin_favorite_action_response{
Status_code: 3,
Status_msg: "点赞事务失败",
}, nil
}
req.Action_type == 2时,从Favorite表中删除并更新Video点赞数:
if err := l.svcCtx.FavoriteModel.TransCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
_, err := l.svcCtx.FavoriteModel.TransDeleteByVideoIdAndUserId(ctx, session, req.Video_id, user_id)
if err != nil {
return err
}
if _, err := l.svcCtx.VideoModel.TransUpdateFavoriteDesc(ctx, session, req.Video_id); err != nil {
return err
}
return nil
}); err != nil {
return &types.Douyin_favorite_action_response{
Status_code: 3,
Status_msg: "取消点赞事务失败",
}, nil
}
至此,我们就利用go-zero框架完成了一次事务操作。类似的,评论和关注也采用这个事务流程,注意关注操作时需要同时更新Followee和Follower的数据。