-
-
Notifications
You must be signed in to change notification settings - Fork 98
/
TransactionAspectSupport.go
122 lines (115 loc) · 3.27 KB
/
TransactionAspectSupport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package GoMybatis
import (
"fmt"
"github.com/zhuxiujia/GoMybatis/tx"
"github.com/zhuxiujia/GoMybatis/utils"
"reflect"
"strings"
)
//使用AOP切面 代理目标服务,如果服务painc()它的事务会回滚
//默认为单协程模型,如果是多协程调用的情况请开启engine.SetGoroutineIDEnable(true)
func AopProxyService(service interface{}, engine SessionEngine) {
var v = reflect.ValueOf(service)
if v.Kind() != reflect.Ptr {
panic("[GoMybatis] AopProxy service must use ptr arg!")
}
AopProxyServiceValue(v, engine)
}
//使用AOP切面 代理目标服务,如果服务painc()它的事务会回滚
func AopProxyServiceValue(service reflect.Value, engine SessionEngine) {
var beanType = service.Type().Elem()
var beanName = beanType.PkgPath() + beanType.Name()
ProxyValue(service, func(funcField reflect.StructField, field reflect.Value) func(arg ProxyArg) []reflect.Value {
//init data
var propagation = tx.PROPAGATION_NEVER
var nativeImplFunc = reflect.ValueOf(field.Interface())
var txTag, haveTx = funcField.Tag.Lookup("tx")
var rollbackTag = funcField.Tag.Get("rollback")
if haveTx {
propagation = tx.NewPropagation(txTag)
}
var fn = func(arg ProxyArg) []reflect.Value {
var goroutineID int64 //协程id
if engine.GoroutineIDEnable() {
goroutineID = utils.GoroutineID()
} else {
goroutineID = 0
}
var session = engine.GoroutineSessionMap().Get(goroutineID)
if session == nil {
//todo newSession is use service bean name?
var err error
session, err = engine.NewSession(beanName)
defer func() {
if session != nil {
session.Close()
}
engine.GoroutineSessionMap().Delete(goroutineID)
}()
if err != nil {
panic(err)
}
//压入map
engine.GoroutineSessionMap().Put(goroutineID, session)
}
if !haveTx {
var err = session.Begin(session.LastPROPAGATION())
if err != nil {
panic(err)
}
} else {
var err = session.Begin(&propagation)
if err != nil {
panic(err)
}
}
var nativeImplResult = doNativeMethod(funcField, arg, nativeImplFunc, session, engine.Log())
if !haveRollBackType(nativeImplResult, rollbackTag) {
var err = session.Commit()
if err != nil {
panic(err)
}
} else {
var err = session.Rollback()
if err != nil {
panic(err)
}
}
return nativeImplResult
}
return fn
})
}
func doNativeMethod(funcField reflect.StructField, arg ProxyArg, nativeImplFunc reflect.Value, session Session, log Log) []reflect.Value {
defer func() {
err := recover()
if err != nil {
var rollbackErr = session.Rollback()
if rollbackErr != nil {
panic(fmt.Sprint(err) + rollbackErr.Error())
}
if log != nil {
log.Println((fmt.Sprint(err) + " Throw out error will Rollback! from >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " + funcField.Name + "()"))
}
panic(err)
}
}()
return nativeImplFunc.Call(arg.Args)
}
func haveRollBackType(v []reflect.Value, typeString string) bool {
//println(typeString)
if v == nil || len(v) == 0 || typeString == "" {
return false
}
for _, item := range v {
if item.Kind() == reflect.Interface {
//println(typeString+" == " + item.String())
if strings.Contains(item.String(), typeString) {
if !item.IsNil() {
return true
}
}
}
}
return false
}