@@ -71,14 +71,22 @@ type Engined interface {
7171
7272// GetEngine will get a db Engine from this context or return an Engine restricted to this context
7373func GetEngine (ctx context.Context ) Engine {
74+ if e := getEngine (ctx ); e != nil {
75+ return e
76+ }
77+ return x .Context (ctx )
78+ }
79+
80+ // getEngine will get a db Engine from this context or return nil
81+ func getEngine (ctx context.Context ) Engine {
7482 if engined , ok := ctx .(Engined ); ok {
7583 return engined .Engine ()
7684 }
7785 enginedInterface := ctx .Value (enginedContextKey )
7886 if enginedInterface != nil {
7987 return enginedInterface .(Engined ).Engine ()
8088 }
81- return x . Context ( ctx )
89+ return nil
8290}
8391
8492// Committer represents an interface to Commit or Close the Context
@@ -87,10 +95,22 @@ type Committer interface {
8795 Close () error
8896}
8997
90- // TxContext represents a transaction Context
98+ // halfCommitter is a wrapper of Committer.
99+ // It can be closed early, but can't be committed early, it is useful for reusing a transaction.
100+ type halfCommitter struct {
101+ Committer
102+ }
103+
104+ func (* halfCommitter ) Commit () error {
105+ // do nothing
106+ return nil
107+ }
108+
109+ // TxContext represents a transaction Context,
110+ // it will reuse the existing transaction in the parent context or create a new one.
91111func TxContext (parentCtx context.Context ) (* Context , Committer , error ) {
92- if InTransaction (parentCtx ) {
93- return nil , nil , ErrAlreadyInTransaction
112+ if sess , ok := inTransaction (parentCtx ); ok {
113+ return newContext ( parentCtx , sess , true ), & halfCommitter { Committer : sess }, nil
94114 }
95115
96116 sess := x .NewSession ()
@@ -102,20 +122,11 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
102122 return newContext (DefaultContext , sess , true ), sess , nil
103123}
104124
105- // WithTx represents executing database operations on a transaction
106- // This function will always open a new transaction, if a transaction exist in parentCtx return an error.
107- func WithTx (parentCtx context.Context , f func (ctx context.Context ) error ) error {
108- if InTransaction (parentCtx ) {
109- return ErrAlreadyInTransaction
110- }
111- return txWithNoCheck (parentCtx , f )
112- }
113-
114- // AutoTx represents executing database operations on a transaction, if the transaction exist,
125+ // WithTx represents executing database operations on a transaction, if the transaction exist,
115126// this function will reuse it otherwise will create a new one and close it when finished.
116- func AutoTx (parentCtx context.Context , f func (ctx context.Context ) error ) error {
117- if InTransaction (parentCtx ) {
118- return f (newContext (parentCtx , GetEngine ( parentCtx ) , true ))
127+ func WithTx (parentCtx context.Context , f func (ctx context.Context ) error ) error {
128+ if sess , ok := inTransaction (parentCtx ); ok {
129+ return f (newContext (parentCtx , sess , true ))
119130 }
120131 return txWithNoCheck (parentCtx , f )
121132}
@@ -202,25 +213,25 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) {
202213
203214// InTransaction returns true if the engine is in a transaction otherwise return false
204215func InTransaction (ctx context.Context ) bool {
205- var e Engine
206- if engined , ok := ctx .(Engined ); ok {
207- e = engined .Engine ()
208- } else {
209- enginedInterface := ctx .Value (enginedContextKey )
210- if enginedInterface != nil {
211- e = enginedInterface .(Engined ).Engine ()
212- }
213- }
216+ _ , ok := inTransaction (ctx )
217+ return ok
218+ }
219+
220+ func inTransaction (ctx context.Context ) (* xorm.Session , bool ) {
221+ e := getEngine (ctx )
214222 if e == nil {
215- return false
223+ return nil , false
216224 }
217225
218226 switch t := e .(type ) {
219227 case * xorm.Engine :
220- return false
228+ return nil , false
221229 case * xorm.Session :
222- return t .IsInTx ()
230+ if t .IsInTx () {
231+ return t , true
232+ }
233+ return nil , false
223234 default :
224- return false
235+ return nil , false
225236 }
226237}
0 commit comments