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:
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user