@@ -71,14 +71,22 @@ type Engined interface {
71
71
72
72
// GetEngine will get a db Engine from this context or return an Engine restricted to this context
73
73
func 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 {
74
82
if engined , ok := ctx .(Engined ); ok {
75
83
return engined .Engine ()
76
84
}
77
85
enginedInterface := ctx .Value (enginedContextKey )
78
86
if enginedInterface != nil {
79
87
return enginedInterface .(Engined ).Engine ()
80
88
}
81
- return x . Context ( ctx )
89
+ return nil
82
90
}
83
91
84
92
// Committer represents an interface to Commit or Close the Context
@@ -87,10 +95,22 @@ type Committer interface {
87
95
Close () error
88
96
}
89
97
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.
91
111
func 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
94
114
}
95
115
96
116
sess := x .NewSession ()
@@ -102,20 +122,11 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
102
122
return newContext (DefaultContext , sess , true ), sess , nil
103
123
}
104
124
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,
115
126
// 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 ))
119
130
}
120
131
return txWithNoCheck (parentCtx , f )
121
132
}
@@ -202,25 +213,25 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) {
202
213
203
214
// InTransaction returns true if the engine is in a transaction otherwise return false
204
215
func 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 )
214
222
if e == nil {
215
- return false
223
+ return nil , false
216
224
}
217
225
218
226
switch t := e .(type ) {
219
227
case * xorm.Engine :
220
- return false
228
+ return nil , false
221
229
case * xorm.Session :
222
- return t .IsInTx ()
230
+ if t .IsInTx () {
231
+ return t , true
232
+ }
233
+ return nil , false
223
234
default :
224
- return false
235
+ return nil , false
225
236
}
226
237
}
0 commit comments