New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Always reuse transaction #22362
Always reuse transaction #22362
Conversation
Codecov Report
@@ Coverage Diff @@
## main #22362 +/- ##
=========================================
+ Coverage 0 48.13% +48.13%
=========================================
Files 0 1046 +1046
Lines 0 142384 +142384
=========================================
+ Hits 0 68535 +68535
- Misses 0 65667 +65667
- Partials 0 8182 +8182
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
// halfCommitter is a wrapper of Committer. | ||
// It can be closed early, but can't be committed early, it is useful for reusing a transaction. | ||
type halfCommitter struct { | ||
Committer | ||
} | ||
|
||
func (*halfCommitter) Commit() error { | ||
// do nothing | ||
return nil | ||
} | ||
|
||
// TxContext represents a transaction Context, | ||
// it will reuse the existing transaction in the parent context or create a new one. | ||
func TxContext(parentCtx context.Context) (*Context, Committer, error) { | ||
if InTransaction(parentCtx) { | ||
return nil, nil, ErrAlreadyInTransaction | ||
if sess, ok := inTransaction(parentCtx); ok { | ||
return newContext(parentCtx, sess, true), &halfCommitter{Committer: sess}, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not sure if this is the definitive answer.
I'll accept it for now, but I think it would be better if Commit
would still be possible with the behavior that it opens a new transaction afterward.
* upstream/main: Replace `can not` with `cannot` (go-gitea#22372) Fix set system setting failure once it cached (go-gitea#22333) Bump json5 from 1.0.1 to 1.0.2 (go-gitea#22365) Always reuse transaction (go-gitea#22362) make /{username}.png redirect to user/org avatar (go-gitea#22356) Remove old HookEventType (go-gitea#22358)
After #22362, we can feel free to use transactions without `db.DefaultContext`. And there are still lots of models using `db.DefaultContext`, I think we should refactor them carefully and one by one. Co-authored-by: Lunny Xiao <[email protected]>
Related to #22362. I overlooked that there's always `committer.Close()`, like: ```go ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil } defer committer.Close() // ... if err != nil { return nil } // ... return committer.Commit() ``` So the `Close` of `halfCommitter` should ignore `commit and close`, it's not a rollback. See: [Why `halfCommitter` and `WithTx` should rollback IMMEDIATELY or commit LATER](#22366 (comment)). Co-authored-by: techknowlogick <[email protected]>
After go-gitea#22362, we can feel free to use transactions without `db.DefaultContext`. And there are still lots of models using `db.DefaultContext`, I think we should refactor them carefully and one by one. Co-authored-by: Lunny Xiao <[email protected]>
Related to go-gitea#22362. I overlooked that there's always `committer.Close()`, like: ```go ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil } defer committer.Close() // ... if err != nil { return nil } // ... return committer.Commit() ``` So the `Close` of `halfCommitter` should ignore `commit and close`, it's not a rollback. See: [Why `halfCommitter` and `WithTx` should rollback IMMEDIATELY or commit LATER](go-gitea#22366 (comment)). Co-authored-by: techknowlogick <[email protected]>
I don't see any cases where we have to create a new transaction instead of reusing the transaction in context. So:
WithTx
andAutoTx
toWithTx
, and it always reuses the transaction if it exists;TxContext
reuse the transaction if it exists, and it will returnhalfCommitter
when reusing.halfCommitter
implementsCommitter
, but it does nothing when committing, so it's possible to close a reused transaction early, but impossible to commit it early.ErrAlreadyInTransaction
, I don't see anyerrors.Is(err, db.ErrAlreadyInTransaction)
, and we don't need it any longer.After this, we can refactor
db.TxContext(db.DefaultContext)
todb.TxContext(ctx)
safely, and feel free to usedb.TxContext
ordb.WithTx
in (almost) any functions as long as there is actx
. I know it's better to usedb.WithTx
instead ofdb.TxContext
, but for refactoring, I don't think so, it will cause lots of lines to change because an anonymous function is required.