-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathspring-transaction-5.3.27.drawio
481 lines (481 loc) · 133 KB
/
spring-transaction-5.3.27.drawio
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
<mxfile host="Electron" modified="2024-11-21T09:07:47.555Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.5 Chrome/114.0.5735.243 Electron/25.3.1 Safari/537.36" etag="vjlJm7q3n__PZ_-uNIYd" version="21.6.5" type="device">
<diagram name="第 1 页" id="EUVRpC5VqprH-hu82ChB">
<mxGraphModel dx="3847" dy="837" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="7g7w9DKIwCULyIwxDFRv-1" value="<h1 style="font-size: 16px;"><font style="font-size: 16px;">Spring 编程式事务 工作原理(5.3.27)</font></h1><div style="font-size: 11px;"><font style="font-size: 11px;">这里重新梳理Spring编程式事务的原理和事务传播机制,之前画的图太罗嗦了。<br>测试代码:SpringBoot-Labs/spring-transaction/spring-programmatic-transaction</font></div><div style="font-size: 11px;"><font style="font-size: 11px;"><br></font></div><div style="font-size: 11px;"><font style="font-size: 11px;">关键内容:</font></div><div style="font-size: 11px;"><font style="font-size: 11px;">1. 触发回滚的两种方式:抛异常、设置 rollbackOnly 标志;</font></div><div style="font-size: 11px;"><font style="font-size: 11px;">2. 如何实现编程式事务,外部事务和内部事务使用不同的传播行为?@Transactional 是怎么处理内部事务使用不同传播行为的;<br><font color="#007fff">&nbsp; &nbsp; TransactionTemplate 对设置多个传播行为支持的不太好(不过可以用try-finally修改传播行为,事务执行完毕再改回去);<br>&nbsp; &nbsp; 推荐直接通过&nbsp;transactionManager.getTransaction(def) 开启事务,每个子事务用独立的 TransactionDefinition 对象定义;</font></font></div><div style="font-size: 11px;"><font style="font-size: 11px;"><font color="#007fff">&nbsp; &nbsp; @Transactional 定义的属性被解析为 TransactionAttributeSource, 每个事务都有自己的事务属性对象。</font></font></div><div style="font-size: 11px;"><font style="font-size: 11px;">3. 事务传播行为的内部实现原理</font></div><p></p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" vertex="1" parent="1">
<mxGeometry x="40" y="10" width="640" height="180" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-34" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-2" target="7g7w9DKIwCULyIwxDFRv-33">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-35" value="3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-34">
<mxGeometry x="0.4083" relative="1" as="geometry">
<mxPoint x="10" y="-39" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-2" value="<font color="#007fff"><b>//1 配置数据源</b></font><br>final DataSource ds = new DriverManagerDataSource(url, user, password);<br><b><font color="#007fff">//2 创建带事务管理的数据源客户端</font></b><br>final TransactionTemplate template = new TransactionTemplate();<br>template.setTransactionManager(new DataSourceTransactionManager(ds));<br><font color="#007fff">// 设置隔离级别</font><br>//template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);<br><br><font color="#007fff"><b>//3 执行事务</b></font><br><div>template.<b>execute</b>(new TransactionCallback&lt;Object&gt;() {</div><div>&nbsp; &nbsp; @Override</div><div>&nbsp; &nbsp; public Object <b>doInTransaction</b>(TransactionStatus status) {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; //获取连接, 创建事务时已经创建了连接并缓存到了线程本地,此工具类会优先从线程本地获取所以不会获取到不同的连接</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; Connection conn = DataSourceUtils.<b>getConnection</b>(ds);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Object savePoint = null;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PreparedStatement prepare = conn.prepareStatement("insert into account (accountName, user, money) values (?, ?, ?)");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.setString(1, "111");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.setString(2, "aaa");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.setInt(3, 1000);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.<b>executeUpdate</b>();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //设置保存点,通过保存点可以实现事务执行失败后回滚到某个保存点而不是回滚全部</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; savePoint = status.<b>createSavepoint</b>();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PreparedStatement prepare = conn.prepareStatement("update account set money=money+100 where user=?");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.setString(1, "aaa");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prepare.<b>executeUpdate</b>();</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //模拟运行时异常</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new RuntimeException("test");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><font color="#007fff"><span style="white-space: pre;">	</span>// 下面自定义异常处理先于 TransactionTemplate 中已定义的 RuntimeException Error Throwable 异常处理的执行</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; } catch (SQLException e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new RuntimeException(e);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("更新失败");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(savePoint != null) {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //回退到保存点</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("回退到保存点");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status.<b>rollbackToSavepoint</b>(savePoint);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //完全回退</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("完全回退");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status.<b>setRollbackOnly</b>();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return null;</div><div>&nbsp; &nbsp; }</div><div>});</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" vertex="1" parent="1">
<mxGeometry x="280" y="200" width="440" height="680" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-4" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-3" target="7g7w9DKIwCULyIwxDFRv-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-3" value="SpringTransactionExample" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="40" y="200" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-9" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-5" target="7g7w9DKIwCULyIwxDFRv-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-5" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">AbstractDriverBasedDataSource</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><b>//连接URL</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private String url;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private String username;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private String password;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private String catalog;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><b>// 默认连接的库</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private String schema;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><b>// 连接属性</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private Properties connectionProperties;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-440" y="480" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-10" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-6" target="7g7w9DKIwCULyIwxDFRv-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-6" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">DriverManagerDataSource</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="-440" y="720" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-11" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-7" target="7g7w9DKIwCULyIwxDFRv-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-7" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">AbstractDataSource</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff" style="font-size: 11px;">没有字段,只是为一些方法提供了默认的实现,以及拓展了方法</font></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-440" y="360" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-8" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">DataSource</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><b style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">重要方法:</font></b></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff" style="font-size: 11px;">// 获取到数据源的连接</font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">Connection getConnection() throws SQLException;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">Connection getConnection(String username, String password)</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">&nbsp; &nbsp; throws SQLException;</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-440" y="200" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-16" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-12" target="7g7w9DKIwCULyIwxDFRv-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-31" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-12" target="7g7w9DKIwCULyIwxDFRv-25">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-12" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>TransactionTemplate</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 事务管理器</font></p><p style="margin: 0px 0px 0px 4px;">private <b>PlatformTransactionManager</b> <b>transactionManager</b>;<br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="-880" y="720" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-15" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-13" target="7g7w9DKIwCULyIwxDFRv-14">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-13" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>DefaultTransactionDefinition</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">事务定义,由于被TransactionTemplate继承可见是针对连接的事务配置</font></b></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">public static final String PREFIX_PROPAGATION = "PROPAGATION_";</p><p style="margin: 0px 0px 0px 4px;">public static final String PREFIX_ISOLATION = "ISOLATION_";</p><p style="margin: 0px 0px 0px 4px;">public static final String PREFIX_TIMEOUT = "timeout_";</p><p style="margin: 0px 0px 0px 4px;">public static final String READ_ONLY_MARKER = "readOnly";</p><p style="margin: 0px 0px 0px 4px;">static final Constants constants = new Constants(TransactionDefinition.class);</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务传播行为,这里可以看到默认的是 REQUIRED (0)</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>propagationBehavior</b> = PROPAGATION_REQUIRED;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务隔离级别</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>isolationLevel</b> = ISOLATION_DEFAULT;、</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务执行超时时间</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>timeout</b> = TIMEOUT_DEFAULT;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//是否是只读事务,只读事务可以优化性能</font></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>readOnly</b> = false;</p><p style="margin: 0px 0px 0px 4px;">private String <b>name</b>;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-880" y="400" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-14" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>TransactionOperations</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;">重要方法:</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 带返回值的事务执行方法</font></p><p style="margin: 0px 0px 0px 4px;">&lt;T&gt; T execute(TransactionCallback&lt;T&gt; action) throws TransactionException;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 不带返回值的事务执行方法</font><br></p><p style="margin: 0px 0px 0px 4px;">default void executeWithoutResult(Consumer&lt;TransactionStatus&gt; action) throws TransactionException<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//</font></p><p style="margin: 0px 0px 0px 4px;">static <b>TransactionOperations</b> withoutTransaction()<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-880" y="200" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-20" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;rounded=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-21" target="7g7w9DKIwCULyIwxDFRv-25">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-21" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">AbstractPlatformTransactionManager</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;">public static final int SYNCHRONIZATION_ALWAYS = 0;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">public static final int SYNCHRONIZATION_NEVER = 2;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private static final Constants constants = new <br>&nbsp; &nbsp; Constants(AbstractPlatformTransactionManager.class);</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><span style="background-color: initial;"><br></span></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><span style="background-color: initial;">private int </span><b style="background-color: initial;">transactionSynchronization</b><span style="background-color: initial;"> = 0;</span><br></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private int defaultTimeout = -1;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff">// 是否允许嵌套事务,DataSourceTransactionManager 构造方法将此字段设置为了 true</font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean <b>nestedTransactionAllowed</b> = false;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean validateExistingTransaction = false;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean globalRollbackOnParticipationFailure = true;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean failEarlyOnGlobalRollbackOnly = false;</p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean rollbackOnCommitFailure = false;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-1320" y="360" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-22" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;rounded=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-24" target="7g7w9DKIwCULyIwxDFRv-21">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-23" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;rounded=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-24" target="7g7w9DKIwCULyIwxDFRv-27">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-1220" y="660" />
<mxPoint x="-1560" y="660" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-32" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-24" target="7g7w9DKIwCULyIwxDFRv-8">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-460" y="710" />
<mxPoint x="-460" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-24" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 11px;"><b style="font-size: 11px;">DataSourceTransactionManager</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><span style="background-color: initial;"><font color="#007fff">//一个事务管理器只用于某个数据源</font></span></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><span style="background-color: initial;">private DataSource </span><b style="background-color: initial;">dataSource</b><span style="background-color: initial;">;</span><br></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;">private boolean <b>enforceReadOnly</b>;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="-1320" y="680" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-25" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>PlatformTransactionManager (I)</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;">TransactionStatus <b>getTransaction</b>(@Nullable TransactionDefinition definition) throws TransactionException;</p><p style="margin: 0px 0px 0px 4px;">void <b>commit</b>(TransactionStatus status) throws TransactionException;</p><p style="margin: 0px 0px 0px 4px;">void <b>rollback</b>(TransactionStatus status) throws TransactionException;</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-1320" y="200" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-26" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;rounded=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-27" target="7g7w9DKIwCULyIwxDFRv-25">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-27" value="<div style="text-align: center;"><b>ResourceTransactionManager</b><b style="background-color: initial;">&nbsp;(I)</b></div><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;">Object getResourceFactory();<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-1760" y="360" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-28" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;rounded=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-29" target="7g7w9DKIwCULyIwxDFRv-24">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-29" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>JdbcTransactionManager</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;">private static final boolean shouldIgnoreXml = <br>&nbsp; &nbsp; SpringProperties.getFlag("spring.xml.ignore");</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//&nbsp;</font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private volatile <b>SQLExceptionTranslator</b> <b>exceptionTranslator</b>;</span><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;"><font color="#007fff">// 懒初始化,默认为true</font></span></p><p style="margin: 0px 0px 0px 4px;">private boolean lazyInit;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-1320" y="840" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-37" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-33" target="7g7w9DKIwCULyIwxDFRv-36">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1210" y="380" />
<mxPoint x="1210" y="520" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-74" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-37">
<mxGeometry x="0.8736" y="-2" relative="1" as="geometry">
<mxPoint x="-9" y="-2" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-76" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-33" target="7g7w9DKIwCULyIwxDFRv-75">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1210" y="380" />
<mxPoint x="1210" y="2260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-77" value="3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-76">
<mxGeometry x="0.955" y="-1" relative="1" as="geometry">
<mxPoint x="11" y="9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-107" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-33" target="7g7w9DKIwCULyIwxDFRv-106">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1210" y="380" />
<mxPoint x="1210" y="2460" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-108" value="4" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-107">
<mxGeometry x="0.982" y="-4" relative="1" as="geometry">
<mxPoint x="-3" y="-4" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-33" value="<div><font color="#007fff">// 暂时没用到过这种事务管理器暂略</font></div><div>if (this.transactionManager instanceof <b>CallbackPreferringPlatformTransactionManager</b>) {</div><div>&nbsp; &nbsp; return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);</div><div>}</div><div>else {</div><div><b>&nbsp; &nbsp; <font color="#007fff">// 1 获取事务状态,事务状态中包含事务对象</font></b></div><div>&nbsp; &nbsp; TransactionStatus status = this.transactionManager.<b>getTransaction</b>(this);</div><div>&nbsp; &nbsp; T result;</div><div>&nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <font color="#007fff"><b>// 2 操作在事务中执行(就是自动提交已经关闭)</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; result = action.<b>doInTransaction</b>(status);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (<b>RuntimeException</b> | <b>Error</b> ex) { <font color="#007fff">// 回滚并重新抛出</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; <b>// 3 回滚</b></font></div><div><span style="background-color: initial;">&nbsp; &nbsp; &nbsp; &nbsp; <b>rollbackOnException</b>(status, ex);</span><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw <b>ex</b>;&nbsp; <font color="#007fff">//内部异常总是继续往外抛</font></div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (<b>Throwable</b> ex) {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; <b>// 3 回滚,如果有被挂起的外部事务会恢复</b></font></div><div><span style="background-color: initial;">&nbsp; &nbsp; &nbsp; &nbsp; <b>rollbackOnException</b>(status, ex);<font color="#007fff"> // 回滚并重新抛出 UndeclaredThrowableException</font></span><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw new <b>UndeclaredThrowableException</b>(ex, "TransactionCallback threw undeclared checked exception");</div><div>&nbsp; &nbsp; }</div><div><b>&nbsp; &nbsp; <font color="#007fff">// 4 事务执行正常提交,如果有被挂起的外部事务会恢复</font></b></div><div>&nbsp; &nbsp; this.transactionManager.<b>commit</b>(status);</div><div>&nbsp; &nbsp; return result;</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" vertex="1" parent="1">
<mxGeometry x="760" y="200" width="440" height="360" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-41" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-36" target="7g7w9DKIwCULyIwxDFRv-40">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1690" y="520" />
<mxPoint x="1690" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-50" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-41">
<mxGeometry x="0.8801" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-52" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-36" target="7g7w9DKIwCULyIwxDFRv-51">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1690" y="520" />
<mxPoint x="1690" y="780" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-53" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-52">
<mxGeometry x="0.4634" y="2" relative="1" as="geometry">
<mxPoint x="8" y="51" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-55" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-36" target="7g7w9DKIwCULyIwxDFRv-54">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1690" y="520" />
<mxPoint x="1690" y="1440" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-56" value="3.1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-55">
<mxGeometry x="0.8772" y="-1" relative="1" as="geometry">
<mxPoint x="11" y="19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-61" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-36" target="7g7w9DKIwCULyIwxDFRv-60">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1690" y="520" />
<mxPoint x="1690" y="1800" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-62" value="3.2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-61">
<mxGeometry x="0.9599" relative="1" as="geometry">
<mxPoint x="4" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-36" value="<div><span style="background-color: initial;">TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());</span></div><div><span style="background-color: initial;"><font color="#007fff"><b>//1 创建事务对象,本质是获取连接,事务的实现本质还是借助的JDBC的事务接口</b></font></span></div><div><span style="background-color: initial;">Object transaction = <b>doGetTransaction</b>();<br></span></div><div>...</div><div><br></div><div><b><font color="#007fff">//2 是否已经存在事务,如果已经存在事务,根据事务传播行为对应处理</font></b></div><div><div>if (<b>isExistingTransaction</b>(transaction)) {</div><div><span style="background-color: initial;">&nbsp; &nbsp; <b>return</b> <b>handleExistingTransaction</b>(def, transaction, debugEnabled);</span><br></div><div>}</div><div><br></div><div><b><font color="#007fff">//3 后面是针对还不存在事务的情况下各种事务传播行为的处理</font></b></div><div>...</div><div><span style="background-color: initial;"><font color="#007fff">//&nbsp;</font></span><font color="#007fff"><b>MANDATORY</b>是指之前存在事务就加入之前的事务,之前没有事务抛异常</font></div><div><font color="#007fff">// 这里不存在事务,所以这里需要抛异常</font></div><div><span style="background-color: initial;">if (def.getPropagationBehavior() == TransactionDefinition.<b>PROPAGATION_MANDATORY</b>) {</span><br></div><div>&nbsp; &nbsp; throw new IllegalTransactionStateException(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "No existing transaction found for transaction marked with propagation 'mandatory'");</div><div>}</div><div><font color="#007fff"><b>// REQUIRED REQUIRES_NEW NESTED&nbsp;</b></font></div><div>else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||</div><div>&nbsp; &nbsp; &nbsp; &nbsp; def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||</div><div>&nbsp; &nbsp; &nbsp; &nbsp; def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {</div><div>&nbsp; &nbsp; <b><font color="#007fff">// 3.1 这里传null且 TransactionSynchronization 钩子未开启情况下方法里面实际不会做任何事</font></b></div><div>&nbsp; &nbsp; SuspendedResourcesHolder suspendedResources = <b>suspend</b>(null);</div><div>&nbsp; &nbsp; if (debugEnabled) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; try {</div><div><b>&nbsp; &nbsp; &nbsp; &nbsp; <font color="#007fff">//3.2 启动事务,并返回事务状态</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>return</b> <b>startTransaction</b>(def, <b>transaction</b>, debugEnabled, suspendedResources);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (RuntimeException | Error ex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <font color="#007fff">//3.3 前面 suspend 如果有挂起,这里需要恢复</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>resume</b>(null, suspendedResources);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; }</div><div>}</div><div><b><font color="#007fff">// SUPPORTS NOT_SUPPORTED&nbsp; NEVER</font></b></div><div><b><font color="#007fff">// 这三种传播行为,在外部没有事务的情况下,普通执行</font></b></div><div>else {</div><div><font color="#007fff">&nbsp; &nbsp; // Create "empty" transaction: no actual transaction, but potentially synchronization.</font></div><div>&nbsp; &nbsp; if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT &amp;&amp; logger.isWarnEnabled()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; logger.warn("Custom isolation level specified but no actual transaction initiated; " +</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "isolation level will effectively be ignored: " + def);</div><div>&nbsp; &nbsp; }</div><div><font color="#007fff"><b>&nbsp; &nbsp; // 3.2</b></font></div><div>&nbsp; &nbsp; boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);</div><div>&nbsp; &nbsp; <b>return</b> <b>prepareTransactionStatus</b>(def, null, true, newSynchronization, debugEnabled, null);</div><div>}</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="1240" y="200" width="440" height="640" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-38" value="TransactionTemplate" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="915" y="170" width="130" height="30" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-39" value="AbstractPlatformTransactionManager" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="1351" y="170" width="220" height="30" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-40" value="<div><div>protected Object <b>doGetTransaction</b>() {</div><div>&nbsp; &nbsp; DataSourceTransactionObject txObject = new <b>DataSourceTransactionObject</b>();</div><div><font color="#007fff">&nbsp; &nbsp; //此Demo中允许使用保存点</font></div><div>&nbsp; &nbsp; txObject.<b>setSavepointAllowed</b>(this.isNestedTransactionAllowed());</div><div><font color="#007fff">&nbsp; &nbsp; //连接容器, 这里只是从 ThreadLocal 中取当前线程和数据源对应的连接容器,没有设置过的话返回null, 这里不会创建连接容器</font></div><div>&nbsp; &nbsp; ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager<br>&nbsp; &nbsp; &nbsp; &nbsp; .<b>getResource</b>(this.obtainDataSource());</div><div>&nbsp; &nbsp; txObject.<b>setConnectionHolder</b>(conHolder, false);</div><div>&nbsp; &nbsp; return txObject;</div><div>}</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=5;" vertex="1" parent="1">
<mxGeometry x="1720" y="200" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-47" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-42" target="7g7w9DKIwCULyIwxDFRv-43">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-42" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>DataSourceTransactionManager$</b><br style="font-size: 11px;"></p><div style="text-align: center;"><b>DataSourceTransactionObject</b></div><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//是否更新了ConnectionHolder</font></p><p style="margin: 0px 0px 0px 4px;">private boolean newConnectionHolder;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务开启实际就是通过关闭自动提交开始的,</font><span style="color: rgb(0, 127, 255); background-color: initial;">有关闭操作,就需要通过此字段记录一下,在事务执行完毕后还要恢复自动提交;如果是内部事务则不需要记录</span></p><p style="margin: 0px 0px 0px 4px;">private boolean mustRestoreAutoCommit;<br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="-440" y="1440" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-46" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;dashed=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-43" target="7g7w9DKIwCULyIwxDFRv-44">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-48" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-43" target="7g7w9DKIwCULyIwxDFRv-45">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-43" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>JdbcTransactionObjectSupport</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><b><font color="#007fff">JDBC接口规范的事务对象实现,本质还是借助JDBC连接的事务接口实现</font></b></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><b><font color="#007fff"><br></font></b></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><b><font color="#007fff">//连接容器</font></b></p><p style="margin: 0px 0px 0px 4px;">private ConnectionHolder <b>connectionHolder</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务执行之前的事务隔离级别,可以在事务执行之后通过这个记录进行恢复</font></p><p style="margin: 0px 0px 0px 4px;">private Integer <b>previousIsolationLevel</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//是否是只读事务</font></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>readOnly</b> = false;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//是否允许使用保存点</font></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>savepointAllowed</b> = false;<br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-440" y="1200" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-44" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>SavepointManager</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff">保存点管理器,可以创建保存点、销毁保存点、让事务回滚到保存点</font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><br></font></p><p style="margin: 0px 0px 0px 4px;">Object createSavepoint() throws TransactionException;<br></p><p style="margin: 0px 0px 0px 4px;">void rollbackToSavepoint(Object savepoint) throws TransactionException;<br></p><p style="margin: 0px 0px 0px 4px;">void releaseSavepoint(Object savepoint) throws TransactionException;<br></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-440" y="1040" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-45" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>SmartTransactionObject</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff">智能事务对象</font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><br></font></p><p style="margin: 0px 0px 0px 4px;"><font style="" color="#007fff">//事务内部是否被标记为了只回滚</font></p><p style="margin: 0px 0px 0px 4px;">boolean isRollbackOnly();<br></p><p style="margin: 0px 0px 0px 4px;">void flush();<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-880" y="1040" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-84" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;endArrow=open;endFill=0;exitX=1.003;exitY=0.392;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-49" target="7g7w9DKIwCULyIwxDFRv-83">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-49" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>TransactionSynchronizationManager</b><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">内部包含一组 ThreadLocal 对象</font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// Key: 数据源对象,Value: ConnectionHolder,即每个线程针对每个数据源对象有一个连接,</b>为了复用连接对象</font></p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;Map&lt;Object, Object&gt;&gt; <b>resources</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Transactional resources");</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 新建事务启动后会创建创建一个set集合存储 TransactionSynchronization, 这个类可以用于注册一些钩子方法,用于功能拓展</b></font></p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;Set&lt;TransactionSynchronization&gt;&gt; <br>&nbsp; &nbsp; <b>synchronizations</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Transaction synchronizations");</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 当前线程绑定的真是事务的名称</font></p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;String&gt; <b>currentTransactionName</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Current transaction name");</p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;Boolean&gt; <b>currentTransactionReadOnly</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Current transaction read-only status");</p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;Integer&gt; <b>currentTransactionIsolationLevel</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Current transaction isolation level");</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 当前线程是否绑定了一个激活的真实事务</font></p><p style="margin: 0px 0px 0px 4px;">private static final ThreadLocal&lt;Boolean&gt; <b>actualTransactionActive</b> =</p><p style="margin: 0px 0px 0px 4px;">&nbsp; &nbsp; &nbsp; &nbsp; new NamedThreadLocal&lt;&gt;("Actual transaction active");</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="-1320" y="1040" width="400" height="360" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-124" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-51" target="7g7w9DKIwCULyIwxDFRv-54">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2180" y="780" />
<mxPoint x="2180" y="1320" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-125" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-124">
<mxGeometry x="-0.9743" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-51" value="<div style="font-size: 9px;">private TransactionStatus <b>handleExistingTransaction</b>(</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; TransactionDefinition definition, Object transaction, boolean debugEnabled)</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; throws TransactionException {</div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // NEVER 不允许出现事务</font></div><div style="font-size: 9px;">&nbsp; &nbsp; if (definition.getPropagationBehavior() == TransactionDefinition.<b>PROPAGATION_NEVER</b>) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalTransactionStateException(</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Existing transaction found for transaction marked with propagation 'never'");</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // 已存在的事务会被挂起,然后普通执行</font></div><div style="font-size: 9px;">&nbsp; &nbsp; if (definition.getPropagationBehavior() == TransactionDefinition.<b>PROPAGATION_NOT_SUPPORTED</b>) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; Object suspendedResources = <b>suspend</b>(transaction);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; return <b>prepareTransactionStatus</b>(</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; definition, null, false, newSynchronization, debugEnabled, suspendedResources);</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // 已存在的事务会被挂起,然后新建一个事务执行</font></div><div style="font-size: 9px;">&nbsp; &nbsp; if (definition.getPropagationBehavior() == TransactionDefinition.<b>PROPAGATION_REQUIRES_NEW</b>) {</div><div style="font-size: 9px;"><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; // 1 挂起外部事务</b></font></div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; SuspendedResourcesHolder suspendedResources = <b>suspend</b>(transaction);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return <b>startTransaction</b>(definition, transaction, debugEnabled, suspendedResources);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; catch (RuntimeException | Error beginEx) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resumeAfterBeginException(transaction, suspendedResources, beginEx);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw beginEx;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; <font color="#007fff">// 嵌套事务</font></div><div style="font-size: 9px;">&nbsp; &nbsp; if (definition.getPropagationBehavior() == TransactionDefinition.<b>PROPAGATION_NESTED</b>) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (!isNestedTransactionAllowed()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new NestedTransactionNotSupportedException(...);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (useSavepointForNestedTransaction()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DefaultTransactionStatus status =</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>prepareTransactionStatus</b>(definition, transaction, false, false, debugEnabled, null);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status.createAndHoldSavepoint();</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return status;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; else {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Nested transaction through nested begin and commit/rollback calls.</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Usually only for JTA: Spring synchronization might get activated here</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // in case of a pre-existing JTA transaction.</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return <b>startTransaction</b>(definition, transaction, debugEnabled, null);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;"><br style="font-size: 9px;"></div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.</font></div><div style="font-size: 9px;">&nbsp; &nbsp; if (isValidateExistingTransaction()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Constants isoConstants = DefaultTransactionDefinition.constants;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalTransactionStateException(...);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (!definition.isReadOnly()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalTransactionStateException("Participating transaction with definition [" +</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; definition + "] is not marked as read-only but existing transaction is");</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);</div><div style="font-size: 9px;">&nbsp; &nbsp; return <b>prepareTransactionStatus</b>(definition, transaction, false, newSynchronization, debugEnabled, null);</div><div style="font-size: 9px;">}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=9;align=left;arcSize=1;" vertex="1" parent="1">
<mxGeometry x="1720" y="400" width="440" height="760" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-54" value="<div>protected final SuspendedResourcesHolder <b>suspend</b>(@Nullable Object transaction) throws TransactionException {</div><div>&nbsp; &nbsp; if (<b>TransactionSynchronizationManager.isSynchronizationActive</b>()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; List&lt;TransactionSynchronization&gt; suspendedSynchronizations = doSuspendSynchronization();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Object suspendedResources = null;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (transaction != null) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; suspendedResources = <b>doSuspend</b>(transaction);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String name = TransactionSynchronizationManager.getCurrentTransactionName();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>setCurrentTransactionName</b>(null);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>setCurrentTransactionReadOnly</b>(false);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>setCurrentTransactionIsolationLevel</b>(null);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>setActualTransactionActive</b>(false);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new SuspendedResourcesHolder(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; catch (RuntimeException | Error ex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // doSuspend failed - original transaction is still active...</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doResumeSynchronization(suspendedSynchronizations);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; else if (<b>transaction != null</b>) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; // Transaction active but no synchronization active.</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Object suspendedResources = <b>doSuspend</b>(transaction);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return new SuspendedResourcesHolder(suspendedResources);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; // Neither transaction nor synchronization active.</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return null;</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=1;" vertex="1" parent="1">
<mxGeometry x="1720" y="1200" width="440" height="480" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-59" value="<div style="font-size: 10px;"><b>REQUIRED</b>, 如果不存在事务则开启一个事务,如果存在事务则加入之前的事务,总是只有一个事务在执行&nbsp;</div><div style="font-size: 10px;"><b>REQUIRES_NEW</b>, 每次执行新开一个事务,如果当前存在事务,则把当前事务挂起&nbsp;</div><div style="font-size: 10px;">SUPPORTS, 有事务则加入事务,没有事务则普通执行&nbsp;</div><div style="font-size: 10px;"><b>NOT_SUPPORTED</b>, 有事务则暂停该事务,没有则普通执行&nbsp;</div><div style="font-size: 10px;">MANDATORY, 强制有事务,没有事务则报异常&nbsp;</div><div style="font-size: 10px;">NEVER, 有事务则报异常&nbsp;</div><div style="font-size: 10px;"><b>NESTED</b>, 如果之前有事务,则创建嵌套事务,嵌套事务回滚不影响父事务,反之父事务影响嵌套事务</div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=10;" vertex="1" parent="1">
<mxGeometry x="760" y="600" width="480" height="100" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-65" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-60" target="7g7w9DKIwCULyIwxDFRv-64">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-60" value="<div>private TransactionStatus <b>startTransaction</b>(TransactionDefinition definition, Object transaction,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {</div><div>&nbsp; &nbsp; <font color="#007fff">//</font>&nbsp;</div><div><span style="background-color: initial;">&nbsp; &nbsp; boolean newSynchronization = (getTransactionSynchronization() != <br><span style="white-space: pre;">	</span>SYNCHRONIZATION_NEVER);</span></div><div>&nbsp; &nbsp; DefaultTransactionStatus <b>status</b> = <b>newTransactionStatus</b>(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);</div><div>&nbsp; &nbsp; <font color="#007fff">// 启动事务</font></div><div><b>&nbsp; &nbsp; doBegin</b>(transaction, definition);</div><div>&nbsp; &nbsp; <font color="#007fff">//&nbsp;</font></div><div>&nbsp; &nbsp; <b>prepareSynchronization</b>(status, definition);</div><div>&nbsp; &nbsp; return status;</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=3;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="1720" y="1720" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-87" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-63" target="7g7w9DKIwCULyIwxDFRv-86">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-63" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>DefaultTransactionStatus</b><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>事务状态</b></font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 事务对象,本质是连接</b></font></p><p style="margin: 0px 0px 0px 4px;">private final Object <b>transaction</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 是否是创建的新事务?false 是加入外部事务</font></p><p style="margin: 0px 0px 0px 4px;">private final boolean <b>newTransaction</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 是否启用 TransactionSynchronization, 默认 true</font></p><p style="margin: 0px 0px 0px 4px;">private final boolean <b>newSynchronization</b>;</p><p style="margin: 0px 0px 0px 4px;">private final boolean <b>readOnly</b>;</p><p style="margin: 0px 0px 0px 4px;">private final boolean debug;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 被挂起的资源,用于后续恢复</font></p><p style="margin: 0px 0px 0px 4px;">private final Object <b>suspendedResources</b>;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="-1760" y="1240" width="400" height="240" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-69" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-64" target="7g7w9DKIwCULyIwxDFRv-68">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2650" y="1580" />
<mxPoint x="2650" y="1310" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-70" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-69">
<mxGeometry x="0.906" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-64" value="<div>protected void <b>doBegin</b>(Object transaction, TransactionDefinition definition) {</div><div>&nbsp; &nbsp; DataSourceTransactionObject <b>txObject</b> = (DataSourceTransactionObject)transaction;</div><div>&nbsp; &nbsp; Connection <b>con</b> = null;</div><div>&nbsp; &nbsp; try {</div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; // 事务刚启动时可能没有连接,这里需要先获取数据源连接,获取连接之后缓存</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (!txObject.hasConnectionHolder() || <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; txObject.getConnectionHolder().isSynchronizedWithTransaction()) {</div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 1 获取数据源连接</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Connection newCon = this.obtainDataSource().<b>getConnection</b>();</div><div><span style=""><span style="">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>&nbsp; &nbsp; ...<br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; txObject.<b>setConnectionHolder</b>(new ConnectionHolder(newCon), true);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; txObject.getConnectionHolder().setSynchronizedWithTransaction(true);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; con = txObject.getConnectionHolder().getConnection();</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // 这里记录之前的隔离级别只是为了事务执行完毕后恢复</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; txObject.setPreviousIsolationLevel(previousIsolationLevel);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; txObject.setReadOnly(definition.isReadOnly());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (con.getAutoCommit()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; txObject.setMustRestoreAutoCommit(true);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (this.logger.isDebugEnabled()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 事务开启的标志:关闭自动提交,通过 JDBC Connection 接口关闭</b></font></div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; con.<b>setAutoCommit</b>(false);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; this.prepareTransactionalConnection(con, definition);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; txObject.getConnectionHolder().setTransactionActive(true);<font color="#007fff"> //记录事务已激活</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; int timeout = this.determineTimeout(definition);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (timeout != -1) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; txObject.getConnectionHolder().setTimeoutInSeconds(timeout);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (txObject.isNewConnectionHolder()) {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //&nbsp;绑定 connection holder 到 线程,记录到 ThreadLocal&lt;Map&lt;Object, Object&gt;&gt; <b>resources</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>bindResource</b>(this.obtainDataSource(), txObject.getConnectionHolder());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; } <b>catch</b> (Throwable var7) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (txObject.isNewConnectionHolder()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DataSourceUtils.releaseConnection(con, this.obtainDataSource());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; txObject.setConnectionHolder((ConnectionHolder)null, false);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=1;" vertex="1" parent="1">
<mxGeometry x="2200" y="1280" width="440" height="600" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-68" value="<div>DriverManager.getConnection(<br>url, props);</div><div><font color="#007fff">最终调用JDBC的接口获取连接</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2680" y="1280" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-71" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ResourceHolderSupport</b><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;"><br></span></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private boolean </span><b style="background-color: initial;">synchronizedWithTransaction</b><span style="background-color: initial;"> = false;</span><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">//&nbsp;</span></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>rollbackOnly</b> = false;</p><p style="margin: 0px 0px 0px 4px;">private Date deadline;</p><p style="margin: 0px 0px 0px 4px;">private int referenceCount = 0;</p><p style="margin: 0px 0px 0px 4px;">private boolean isVoid = false;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-2200" y="1040" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-73" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-72" target="7g7w9DKIwCULyIwxDFRv-71">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-72" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ConnectionHolder</b><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">连接容器</font></b></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private ConnectionHandle <b>connectionHandle</b>;</span></p><p style="margin: 0px 0px 0px 4px;">private Connection <b>currentConnection</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务是否激活,事务对应的连接的自动提交关闭后设置激活</font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private boolean </span><b style="background-color: initial;">transactionActive</b><span style="background-color: initial;">;</span><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private Boolean <b>savepointsSupported</b>;</span><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private int <b>savepointCounter</b>;</span><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="-2200" y="1240" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-80" value="..." style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-81" target="7g7w9DKIwCULyIwxDFRv-79">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-75" value="<div>this.transactionManager.<b>rollback</b>(status);<br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=center;arcSize=9;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="1240" y="2230" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-89" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-79" target="7g7w9DKIwCULyIwxDFRv-88">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="2260" />
<mxPoint x="2170" y="1950" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-90" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-89">
<mxGeometry x="0.8947" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-94" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-79" target="7g7w9DKIwCULyIwxDFRv-93">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="2260" />
<mxPoint x="2170" y="2050" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-98" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-94">
<mxGeometry x="0.849" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-96" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-79" target="7g7w9DKIwCULyIwxDFRv-95">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="2260" />
<mxPoint x="2170" y="2150" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-97" value="3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-96">
<mxGeometry x="0.7328" y="-2" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-100" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-79" target="7g7w9DKIwCULyIwxDFRv-99">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="2260" />
<mxPoint x="2170" y="2320" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-101" value="4" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-100">
<mxGeometry x="0.6303" y="-2" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-79" value="<div><font color="#007fff">// 方法里面有详细的debug日志,这里省略</font></div><div>private void processRollback(DefaultTransactionStatus status, boolean unexpected) {</div><div>&nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean unexpectedRollback = unexpected;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div><font color="#ff00ff"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 执行所有 TransactionSynchronization beforeCompletion() 钩子方法</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; triggerBeforeCompletion(status);</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 如果有保存点默认回滚到保存点</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (<b>status.hasSavepoint()</b>) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b><font color="#007fff">//1</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status.<b>rollbackToHeldSavepoint</b>();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (<b>status.isNewTransaction()</b>) { <font color="#007fff">//有创建新事务,则事务回滚</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>//2&nbsp;</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>doRollback</b>(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else { <font color="#007fff">//没有创建新事务,即加入了外部事务 或 普通执行</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (status.hasTransaction()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {</div><div><b><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //3 仅仅是在事务对应的连接容器中设置 rollbackOnly = true</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>doSetRollbackOnly</b>(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... 日志 ...</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... 日志 ...</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Unexpected rollback only matters here if we're asked to fail early</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isFailEarlyOnGlobalRollbackOnly()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unexpectedRollback = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; catch (RuntimeException | Error ex) {</div><div><b style=""><font color="#ff00ff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 执行所有 TransactionSynchronization afterCompletion() 钩子方法;回滚失败</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>triggerAfterCompletion</b>(status, TransactionSynchronization.STATUS_UNKNOWN);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div><font color="#ff00ff">&nbsp; &nbsp;<b> &nbsp; &nbsp; // 执行所有 TransactionSynchronization afterCompletion() 钩子方法并清空线程本地 synchronizations 钩子集合;成功回滚</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>triggerAfterCompletion</b>(status, TransactionSynchronization.STATUS_ROLLED_BACK);</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // Raise UnexpectedRollbackException if we had a global rollback-only marker</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (unexpectedRollback) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new UnexpectedRollbackException(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Transaction rolled back because it has been marked as rollback-only");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; finally {</div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; //4 事务资源清理,不管事务执行成功还是失败都需要清理</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>cleanupAfterCompletion</b>(status);</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=3;" vertex="1" parent="1">
<mxGeometry x="1720" y="1920" width="440" height="680" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-82" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-75" target="7g7w9DKIwCULyIwxDFRv-81">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1432.12" y="2260" as="sourcePoint" />
<mxPoint x="1711.12" y="2260" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-81" value="<div>processRollback(defStatus, false)<br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=center;arcSize=9;" vertex="1" parent="1">
<mxGeometry x="1480" y="2230" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-83" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>TransactionSynchronization&nbsp;</b><span style="background-color: initial;">extends Ordered, Flushable</span></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><b>事务生命周期拓展钩子,比如事务回滚成功、回滚失败后记录下日志,发个告警等等</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><font color="#007fff"><br></font></p><p style="margin: 0px 0px 0px 4px;">default void suspend()<br></p><p style="margin: 0px 0px 0px 4px;">default void resume()<br></p><p style="margin: 0px 0px 0px 4px;">default void flush()<br></p><p style="margin: 0px 0px 0px 4px;">default void beforeCommit(boolean readOnly)<br></p><p style="margin: 0px 0px 0px 4px;">default void beforeCompletion()<br></p><p style="margin: 0px 0px 0px 4px;">default void afterCommit()<br></p><p style="margin: 0px 0px 0px 4px;">default void afterCompletion(int status)<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="-880" y="1240" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-86" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>AbstractTransactionStatus</b><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>事务状态基本信息</b></font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>//用于将内部操作失败传递给外部事务,外部事务在 commit() 中判断此值决定是回滚还是提交</b></font></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>rollbackOnly</b> = false;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//事务是否执行成功</font></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>completed</b> = false;</p><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">//保存点</font></b></p><p style="margin: 0px 0px 0px 4px;">private Object <b>savepoint</b>;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-1760" y="1040" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-92" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-88" target="7g7w9DKIwCULyIwxDFRv-91">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-88" value="<div style="">Object savepoint = getSavepoint();<br></div><div style=""><div>getSavepointManager().<b>rollbackToSavepoint</b>(savepoint);</div><div>getSavepointManager().releaseSavepoint(savepoint);</div><div>setSavepoint(null);</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;" vertex="1" parent="1">
<mxGeometry x="2200" y="1920" width="440" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-91" value="<div style="">conHolder.getConnection()<br>&nbsp; &nbsp; .<b>rollback</b>((Savepoint) savepoint);<br></div><div style="">conHolder.resetRollbackOnly();<br></div><div style=""><font color="#007fff">最终调用JDBC的接口回滚到保存点</font><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2680" y="1920" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-93" value="<div style="">con.<b>rollback</b>();<br></div><div style=""><font color="#007fff">从事务对象中获取连接后,最终调用JDBC rollback() 方法回滚</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2200" y="2020" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-95" value="DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();<br><font color="#007fff">// 设置事务对象的连接容器的&nbsp;rollbackOnly = true</font><br>txObject.setRollbackOnly();" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;" vertex="1" parent="1">
<mxGeometry x="2200" y="2120" width="440" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-103" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-99" target="7g7w9DKIwCULyIwxDFRv-102">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-105" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-99" target="7g7w9DKIwCULyIwxDFRv-104">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-99" value="<div>private void cleanupAfterCompletion(DefaultTransactionStatus status) {</div><div><font color="#007fff">&nbsp; &nbsp; //更新事务状态 compeleted = true</font></div><div>&nbsp; &nbsp; status.<b>setCompleted</b>();</div><div>&nbsp; &nbsp; if (status.isNewSynchronization()) { <font color="#007fff"><b>// 若启用 TransactionSynchronization 钩子,需要清理线程本地变量</b></font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp;synchronizations、currentTransactionName、currentTransactionReadOnly、currentTransactionIsolationLevel、actualTransactionActive</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; TransactionSynchronizationManager.<b>clear</b>();</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; if (status.isNewTransaction()) {&nbsp;<font color="#007fff"><b>// 新建事务, 需要清理事务资源</b></font></div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; //1 解绑 事务对象 -&gt; ConnectionHolder, 即清除线程本地变量 resources 中当前事务对象对应的连接容器<br></b></font></div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; //2 恢复连接自动提交、恢复事务前的隔离级别、恢复事务前的readOnly配置</b></font></div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; //3 如果事务新建了连接容器,连接还需要释放,并重置连接容器的状态字段</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>doCleanupAfterCompletion</b>(status.getTransaction());</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; if (status.<b>getSuspendedResources</b>() != null) { <b><font color="#007fff">// 被挂起的资源不为空的话还需要恢复</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (status.isDebug()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logger.debug("Resuming suspended transaction after completion of inner transaction");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Object transaction = (status.hasTransaction() ? status.getTransaction() : null);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>resume</b>(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" vertex="1" parent="1">
<mxGeometry x="2200" y="2220" width="440" height="300" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-102" value="con.<b>setAutoCommit</b>(true);<div style=""><font color="#007fff">调用JDBC setAutoCommit() 方法恢复自动提交</font><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2680" y="2300" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-104" value="con.<b>close</b>();<div style=""><font color="#007fff">调用JDBC close() 方法释放连接</font><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2680" y="2380" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-109" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-106" target="7g7w9DKIwCULyIwxDFRv-81">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-112" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-109">
<mxGeometry x="-0.7903" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-111" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-106" target="7g7w9DKIwCULyIwxDFRv-110">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-113" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-111">
<mxGeometry x="-0.7746" relative="1" as="geometry">
<mxPoint x="10" y="512" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-106" value="<div style="">DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;<br></div><div style=""><b><font color="#007fff">// 是否被标记了本地事务回滚,加入外部事务的内部操作失败,外部事务执行回滚,内部失败不是通过异常传给外部事务的,而是通过 rollbackOnly</font></b></div><div style="">if (defStatus.<b>isLocalRollbackOnly</b>()) {&nbsp;</div><div style="">&nbsp; <b>&nbsp; <font color="#007fff">// 1</font></b></div><div style="">&nbsp; &nbsp;&nbsp;<b>processRollback</b>(defStatus, false);</div><div style="">&nbsp; &nbsp; return;</div><div style="">}<br></div><div style=""><font color="#007fff"><b>// 是否被标记了全局事务回滚,用于支持分布式事务(跨连接事务),暂略</b></font></div><div style="">if (<b>!shouldCommitOnGlobalRollbackOnly() &amp;&amp; defStatus.isGlobalRollbackOnly()</b>) {</div><div style="">&nbsp; &nbsp; <b><font color="#007fff">// 1</font></b><br>&nbsp; &nbsp;&nbsp;<b>processRollback</b>(defStatus, true);</div><div style="">&nbsp; &nbsp; return;<br>}</div><div style=""><font color="#007fff"><b>// 2 没有被标记回滚,正常提交</b></font></div><div style=""><b>processCommit</b>(defStatus);<br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=3;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="1241" y="2360" width="440" height="200" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-117" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-110" target="7g7w9DKIwCULyIwxDFRv-116">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="3030" />
<mxPoint x="2170" y="2830" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-121" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-117">
<mxGeometry x="0.9039" y="2" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-119" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-110" target="7g7w9DKIwCULyIwxDFRv-118">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2170" y="3030" />
<mxPoint x="2170" y="2750" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-120" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="7g7w9DKIwCULyIwxDFRv-119">
<mxGeometry x="0.9132" y="3" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-110" value="<div style=""><div>try {</div><div>&nbsp; &nbsp; boolean beforeCompletionInvoked = false;</div><div>&nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; boolean unexpectedRollback = false;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; prepareForCommit(status);</div><div><font color="#ff00ff"><b><span style="white-space: pre;">	</span>//&nbsp; 调用钩子方法</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; triggerBeforeCommit(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; triggerBeforeCompletion(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; beforeCompletionInvoked = true;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (status.hasSavepoint()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unexpectedRollback = status.isGlobalRollbackOnly();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <font color="#007fff">// 1</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status.<b>releaseHeldSavepoint</b>();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; else if (status.isNewTransaction()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unexpectedRollback = status.isGlobalRollbackOnly();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<font color="#007fff"> // 2</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>doCommit</b>(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; else if (isFailEarlyOnGlobalRollbackOnly()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unexpectedRollback = status.isGlobalRollbackOnly();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div><br></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // Throw UnexpectedRollbackException if we have a global rollback-only</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // marker but still didn't get a corresponding exception from commit.</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (unexpectedRollback) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new <b>UnexpectedRollbackException</b>(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Transaction silently rolled back because it has been marked as rollback-only");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (<b>UnexpectedRollbackException</b> ex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (<b>TransactionException</b> ex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (isRollbackOnCommitFailure()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>doRollbackOnCommitException</b>(status, ex);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; catch (<b>RuntimeException | Error </b>ex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (!beforeCompletionInvoked) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; triggerBeforeCompletion(status);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>doRollbackOnCommitException</b>(status, ex);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; throw ex;</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; // Trigger afterCommit callbacks, with an exception thrown there</div><div>&nbsp; &nbsp; // propagated to callers but the transaction still considered as committed.</div><div>&nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; triggerAfterCommit(status);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);</div><div>&nbsp; &nbsp; }</div><div>}</div><div>finally {</div><div>&nbsp; &nbsp; cleanupAfterCompletion(status);</div><div>}</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=3;" vertex="1" parent="1">
<mxGeometry x="1720" y="2640" width="440" height="780" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-115" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" edge="1" parent="1" source="7g7w9DKIwCULyIwxDFRv-114" target="7g7w9DKIwCULyIwxDFRv-21">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-1560" y="670" />
<mxPoint x="-1120" y="670" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-114" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>JtaTransactionManager</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">如果想看下全局事务的原理,可以看下这个事务管理器的实现</font></b></p><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px; font-size: 11px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" vertex="1" parent="1">
<mxGeometry x="-1760" y="840" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-116" value="con.<b>commit</b>();<div style=""><font color="#007fff">调用JDBC commit() 方法提交</font><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2200" y="2800" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-118" value="conHolder.getConnection()<br>.<b>releaseSavepoint</b>((Savepoint) savepoint);<div style=""><font color="#007fff">调用JDBC releaseSavepoint() 方法释放保存点</font><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=9;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2200" y="2720" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="7g7w9DKIwCULyIwxDFRv-127" value="<div><b>注意事项</b>:</div><div><ol><li>内部事务或普通运行抛出的异常不处理,都会被外部事务捕获到,从而导致外部事务也回滚;<br>正确的方式是应该捕获异常,至于是否应该让外部事务也回滚通过设置 rollbackOnly 标志实现。<br><font color="#007fff">编程式事务可以通过&nbsp;TransactionStatus.setRollbackOnly()设置,声明式事务可借助&nbsp;TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 设置。</font></li><li>挂起外部事务开新事务的原理:线程本地存的属性打包到 SuspendResource 对象,然后新建连接并设置新事务属性到线程本地;<br>恢复事务就是将 SuspendResource 对象(内部包括之前的连接)重新设置到线程本地。<br><br></li></ol></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="760" y="10" width="930" height="140" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>