fix(仓储层): 修复事务 ent client 调用 Close() 导致的 panic

问题:创建用户时发生 panic,错误信息为
"interface conversion: sql.ExecQuerier is *sql.Tx, not *sql.DB"

原因:基于事务创建的 ent client 在调用 Close() 时,ent 的 sql driver
会尝试将 ExecQuerier 断言为 *sql.DB 来关闭连接,但实际类型是 *sql.Tx

修复:移除对 txClient.Close() 的调用,事务的清理通过
sqlTx.Rollback() 和 sqlTx.Commit() 完成即可

影响范围:
- user_repo.go: Create 和 Update 方法
- group_repo.go: Delete 方法

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
yangjianbo
2025-12-29 15:49:20 +08:00
parent 305eaabb53
commit 5584709ac9
2 changed files with 9 additions and 15 deletions

View File

@@ -239,7 +239,6 @@ func (r *groupRepository) DeleteCascade(ctx context.Context, id int64) ([]int64,
exec := r.sql
txClient := r.client
var sqlTx *sql.Tx
var txClientClose func() error
if r.begin != nil {
sqlTx, err = r.begin.BeginTx(ctx, nil)
@@ -248,12 +247,11 @@ func (r *groupRepository) DeleteCascade(ctx context.Context, id int64) ([]int64,
}
exec = sqlTx
txClient = entClientFromSQLTx(sqlTx)
txClientClose = txClient.Close
// 注意:不能调用 txClient.Close(),因为基于事务的 ent client
// 在 Close() 时会尝试将 ExecQuerier 断言为 *sql.DB但实际是 *sql.Tx
// 事务的清理通过 sqlTx.Rollback() 和 sqlTx.Commit() 完成
defer func() { _ = sqlTx.Rollback() }()
}
if txClientClose != nil {
defer func() { _ = txClientClose() }()
}
// Lock the group row to avoid concurrent writes while we cascade.
var lockedID int64

View File

@@ -40,7 +40,6 @@ func (r *userRepository) Create(ctx context.Context, userIn *service.User) error
exec := r.sql
txClient := r.client
var sqlTx *sql.Tx
var txClientClose func() error
if r.begin != nil {
var err error
@@ -50,12 +49,11 @@ func (r *userRepository) Create(ctx context.Context, userIn *service.User) error
}
exec = sqlTx
txClient = entClientFromSQLTx(sqlTx)
txClientClose = txClient.Close
// 注意:不能调用 txClient.Close(),因为基于事务的 ent client
// 在 Close() 时会尝试将 ExecQuerier 断言为 *sql.DB但实际是 *sql.Tx
// 事务的清理通过 sqlTx.Rollback() 和 sqlTx.Commit() 完成
defer func() { _ = sqlTx.Rollback() }()
}
if txClientClose != nil {
defer func() { _ = txClientClose() }()
}
created, err := txClient.User.Create().
SetEmail(userIn.Email).
@@ -126,7 +124,6 @@ func (r *userRepository) Update(ctx context.Context, userIn *service.User) error
exec := r.sql
txClient := r.client
var sqlTx *sql.Tx
var txClientClose func() error
if r.begin != nil {
var err error
@@ -136,12 +133,11 @@ func (r *userRepository) Update(ctx context.Context, userIn *service.User) error
}
exec = sqlTx
txClient = entClientFromSQLTx(sqlTx)
txClientClose = txClient.Close
// 注意:不能调用 txClient.Close(),因为基于事务的 ent client
// 在 Close() 时会尝试将 ExecQuerier 断言为 *sql.DB但实际是 *sql.Tx
// 事务的清理通过 sqlTx.Rollback() 和 sqlTx.Commit() 完成
defer func() { _ = sqlTx.Rollback() }()
}
if txClientClose != nil {
defer func() { _ = txClientClose() }()
}
updated, err := txClient.User.UpdateOneID(userIn.ID).
SetEmail(userIn.Email).