1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.cdi;
17
18 import jakarta.inject.Inject;
19 import jakarta.interceptor.AroundInvoke;
20 import jakarta.interceptor.Interceptor;
21 import jakarta.interceptor.InvocationContext;
22 import jakarta.transaction.HeuristicMixedException;
23 import jakarta.transaction.HeuristicRollbackException;
24 import jakarta.transaction.NotSupportedException;
25 import jakarta.transaction.RollbackException;
26 import jakarta.transaction.SystemException;
27
28 import java.io.Serializable;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.UndeclaredThrowableException;
31
32 import org.apache.ibatis.session.SqlSessionManager;
33
34
35
36
37
38
39
40
41
42
43 @Transactional
44 @Interceptor
45 public class LocalTransactionInterceptor implements Serializable {
46
47 private static final long serialVersionUID = 1L;
48
49 @Inject
50 private transient SqlSessionManagerRegistry registry;
51
52
53
54
55
56
57
58
59
60
61
62
63 @AroundInvoke
64 public Object invoke(InvocationContext ctx) throws Exception {
65 Transactional transactional = getTransactionalAnnotation(ctx);
66 boolean isInitiator = start(transactional);
67 boolean isExternalJta = isTransactionActive();
68 if (isInitiator && !isExternalJta) {
69 beginJta();
70 }
71 boolean needsRollback = transactional.rollbackOnly();
72 Object result;
73 try {
74 result = ctx.proceed();
75 } catch (Exception ex) {
76 Exception unwrapped = unwrapException(ex);
77 needsRollback = needsRollback || needsRollback(transactional, unwrapped);
78 throw unwrapped;
79 } finally {
80 if (isInitiator) {
81 try {
82 if (needsRollback) {
83 rollback(transactional);
84 } else {
85 commit(transactional);
86 }
87 } finally {
88 close();
89 endJta(isExternalJta, needsRollback);
90 }
91 }
92 }
93 return result;
94 }
95
96
97
98
99
100
101
102
103
104 protected boolean isTransactionActive() throws SystemException {
105 return false;
106 }
107
108
109
110
111
112
113
114
115
116 protected void beginJta() throws NotSupportedException, SystemException {
117
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 protected void endJta(boolean isExternaTransaction, boolean commit)
138 throws SystemException, RollbackException, HeuristicMixedException, HeuristicRollbackException {
139
140 }
141
142 private boolean needsRollback(Transactional transactional, Throwable throwable) {
143 if (RuntimeException.class.isAssignableFrom(throwable.getClass())) {
144 return true;
145 }
146 for (Class<? extends Throwable> exceptionClass : transactional.rollbackFor()) {
147 if (exceptionClass.isAssignableFrom(throwable.getClass())) {
148 return true;
149 }
150 }
151 return false;
152 }
153
154 protected Transactional getTransactionalAnnotation(InvocationContext ctx) {
155 Transactional t = ctx.getMethod().getAnnotation(Transactional.class);
156 if (t == null) {
157 t = ctx.getMethod().getDeclaringClass().getAnnotation(Transactional.class);
158 }
159 return t;
160 }
161
162 private boolean start(Transactional transactional) {
163 boolean started = false;
164 for (SqlSessionManager manager : this.registry.getManagers()) {
165 if (!manager.isManagedSessionStarted()) {
166 manager.startManagedSession(transactional.executorType(),
167 transactional.isolation().getTransactionIsolationLevel());
168 started = true;
169 }
170 }
171 return started;
172 }
173
174 private void commit(Transactional transactional) {
175 for (SqlSessionManager manager : this.registry.getManagers()) {
176 manager.commit(transactional.force());
177 }
178 }
179
180 private void rollback(Transactional transactional) {
181 for (SqlSessionManager manager : this.registry.getManagers()) {
182 manager.rollback(transactional.force());
183 }
184 }
185
186 private void close() {
187 for (SqlSessionManager manager : this.registry.getManagers()) {
188 manager.close();
189 }
190 }
191
192 private Exception unwrapException(Exception wrapped) {
193 Throwable unwrapped = wrapped;
194 while (true) {
195 if (unwrapped instanceof InvocationTargetException) {
196 unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
197 } else if (unwrapped instanceof UndeclaredThrowableException) {
198 unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
199 } else if (!(unwrapped instanceof Exception)) {
200 return new RuntimeException(unwrapped);
201 } else {
202 return (Exception) unwrapped;
203 }
204 }
205 }
206
207 }