forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransaction.xml
More file actions
2532 lines (2069 loc) · 121 KB
/
transaction.xml
File metadata and controls
2532 lines (2069 loc) · 121 KB
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
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="transaction">
<title>Transaction Management</title>
<section id="transaction-intro">
<title>Introduction to Spring Framework transaction management</title>
<para>Comprehensive transaction support is among the most compelling
reasons to use the Spring Framework. The Spring Framework provides a
consistent abstraction for transaction management that delivers the
following benefits:</para>
<itemizedlist>
<listitem>
<para>Consistent programming model across different transaction APIs
such as Java Transaction API (JTA), JDBC, Hibernate, Java Persistence
API (JPA), and Java Data Objects (JDO).</para>
</listitem>
<listitem>
<para>Support for <link linkend="transaction-declarative">declarative
transaction management</link>.</para>
</listitem>
<listitem>
<para>Simpler API for <link
linkend="transaction-programmatic">programmatic</link> transaction
management than complex transaction APIs such as JTA.</para>
</listitem>
<listitem>
<para>Excellent integration with Spring's data access
abstractions.</para>
</listitem>
</itemizedlist>
<para>The following sections describe the Spring Framework's transaction
value-adds and technologies. (The chapter also includes discussions of
best practices, application server integration, and solutions to common
problems.)</para>
<itemizedlist>
<listitem>
<para><link linkend="transaction-motivation">Advantages of the Spring
Framework's transaction support model</link> describes
<emphasis>why</emphasis> you would use the Spring Framework's
transaction abstraction instead of EJB Container-Managed Transactions
(CMT) or choosing to drive local transactions through a proprietary
API such as Hibernate.</para>
<!--The section (formerly called Motivation) does not mention Hibernate. It talks about local and global. TR: REVISED, PLS REVIEW added 'local' to the sentence-->
</listitem>
<listitem>
<para><link linkend="transaction-strategies">Understanding the Spring
Framework transaction abstraction</link> outlines the core classes and
describes how to configure and obtain
<interfacename>DataSource</interfacename> instances from a variety of
sources.</para>
</listitem>
<listitem>
<para><link linkend="tx-resource-synchronization">Synchronizing
resources with transactions </link>describes how the application code
ensures that resources are created, reused, and cleaned up
properly.<!--Added above link and bullet item. TR: OK--></para>
</listitem>
<listitem>
<para><link linkend="transaction-declarative">Declarative transaction
management</link> describes support for declarative transaction
management.</para>
</listitem>
<listitem>
<para><link linkend="transaction-programmatic">Programmatic
transaction management</link> covers support for programmatic (that
is, explicitly coded) transaction management.</para>
</listitem>
</itemizedlist>
</section>
<section id="transaction-motivation">
<title>Advantages of the Spring Framework's transaction support model<!--Renamed section to make it more to the point. TR: OK--></title>
<para>Traditionally, Java EE developers have had two choices for
transaction management: <emphasis>global</emphasis> or
<emphasis>local</emphasis> transactions, both of which have profound
limitations. Global and local transaction management is reviewed in the
next two sections, followed by a discussion of how the Spring Framework's
transaction management support addresses the limitations of the global and
local transaction models.</para>
<!--Gave global, local, and spring models their own sections. These need to be called out at a higher level, esp. Spring advantage! TR: OK-->
<section id="transaction-global">
<title>Global transactions</title>
<para>Global transactions enable you to work with multiple transactional
resources, typically relational databases and message queues. The
application server manages global transactions through the JTA, which is
a cumbersome API to use (partly due to its exception model).
Furthermore, a JTA <interfacename>UserTransaction</interfacename>
normally needs to be sourced from JNDI, meaning that you
<emphasis>also</emphasis> need to use JNDI in order to use JTA.
Obviously the use of global transactions would limit any potential reuse
of application code, as JTA is normally only available in an application
server environment.</para>
<para>Previously, the preferred way to use global transactions was via
EJB <emphasis>CMT</emphasis> (<emphasis>Container Managed
Transaction</emphasis>): CMT is a form of <emphasis
role="bold">declarative transaction management</emphasis> (as
distinguished from <emphasis role="bold">programmatic transaction
management</emphasis>). EJB CMT removes the need for transaction-related
JNDI lookups, although of course the use of EJB itself necessitates the
use of JNDI. It removes most but not all of the need to write Java code
to control transactions. The significant downside is that CMT is tied to
JTA and an application server environment. Also, it is only available if
one chooses to implement business logic in EJBs, or at least behind a
transactional EJB facade. The negatives of EJB in general are so great
that this is not an attractive proposition, especially in the face of
compelling alternatives for declarative transaction management.</para>
</section>
<section id="transaction-local">
<title>Local transactions</title>
<para>Local transactions are resource-specific, such as a transaction
associated with a JDBC connection. Local transactions may be easier to
use, but have significant disadvantages: they cannot work across
multiple transactional resources. For example, code that manages
transactions using a JDBC connection cannot run within a global JTA
transaction. Because the application server is not involved in
transaction management, it cannot help ensure correctness across
multiple resources. (It is worth noting that most applications use a
single transaction resource.) Another downside is that local
transactions are invasive to the programming model.</para>
</section>
<section id="transaction-programming-model">
<title>Spring Framework's consistent programming model</title>
<para>Spring resolves the disadvantages of global and local
transactions. It enables application developers to use a
<emphasis>consistent</emphasis> programming model <emphasis>in any
environment</emphasis>. You write your code once, and it can benefit
from different transaction management strategies in different
environments. The Spring Framework provides both declarative and
programmatic transaction management. Most users prefer declarative
transaction management, which is recommended in most cases.</para>
<!--Do you need to specify that Spring allows you to work with *multiple* transactional resourcess (as global transactions do)? TR: OK AS IS-->
<para>With programmatic transaction management, developers work with the
Spring Framework transaction abstraction, which can run over any
underlying transaction infrastructure. <!--Re preceding statement, does this mean that next section re transaction abstraction applies only to programmatic tx management?If so--><!--shouldn't the next section be subsection of *Programmatic transaction management* section? However, there is a sentence in the next--><!--section that reads *regardless of whether you opt for declarative or prog. tx man. defining correct PlatformTransactionManager impl. is--><!--absolutely essential.* This is followed by discussion of that impl. So I'm not sure what goes where.
TR: OK AS IS - I think it's fine as is - the concepts apply to both programmatic and declarative transactions
-->With the preferred declarative model, developers typically write little or
no code related to transaction management, and hence do not depend on
the Spring Framework transaction API, or any other transaction
API.</para>
<sidebar>
<title>Do you need an application server for transaction
management?</title>
<para>The Spring Framework's transaction management support changes
traditional rules as to when an enterprise Java application requires
an application server.</para>
<para>In particular, you do not need an application server simply for
declarative transactions through EJBs. In fact, even if your
application server has powerful JTA capabilities, you may decide that
the Spring Framework's declarative transactions offer more power and a
more productive programming model than EJB CMT.</para>
<para>Typically you need an application server's JTA capability only
if your application needs to handle transactions across multiple
resources, which is not a requirement for many applications. Many
high-end applications use a single, highly scalable database (such as
Oracle RAC) instead. Standalone transaction managers such as <ulink
url="http://www.atomikos.com/">Atomikos Transactions</ulink> and
<ulink url="http://jotm.objectweb.org/">JOTM</ulink> are other
options. Of course, you may need other application server capabilities
such as Java Message Service (JMS) and J2EE Connector Architecture
(JCA).</para>
<para>The Spring Framework <emphasis>gives you the choice of when to
scale your application to a fully loaded application
server</emphasis>. Gone are the days when the only alternative to
using EJB CMT or JTA was to write code with local transactions such as
those on JDBC connections, and face a hefty rework if you need that
code to run within global, container-managed transactions. With the
Spring Framework, only some of the bean definitions in your
configuration file, rather than your code, need to change.</para>
<!--CLarify last sentence. Only what kind of configuration has to change?
TR: REVISED, PLS REVIEW - changed to say "some of the bean definitions in your configuration file"-->
</sidebar>
</section>
</section>
<section id="transaction-strategies">
<title>Understanding the Spring Framework transaction abstraction<!--If this section applies only to prog. tx management, we should say that up front. Add info?
TR: OK AS IS - It's relevant for declarative tx as well--></title>
<para>The key to the Spring transaction abstraction is the notion of a
<emphasis>transaction strategy</emphasis>. A transaction strategy is
defined by the
<interfacename>org.springframework.transaction.PlatformTransactionManager</interfacename>
interface:</para>
<programlisting language="java">public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}</programlisting>
<para>This is primarily a service provider interface (SPI), although it
can be used <link
linkend="transaction-programmatic-ptm">programmatically</link> from your
application code. <!--Write out SPI with SPI in parentheses. SPI stands for a number of different things.And does logic of sentence make sense?
TR: REVISED, PLS REVIEW - spelled SPI out and added a bit of clarification at the end-->Because
<interfacename>PlatformTransactionManager</interfacename> is an
<emphasis>interface</emphasis>, it can be easily mocked or stubbed as
necessary. It is not tied to a lookup strategy such as JNDI.
<interfacename>PlatformTransactionManager</interfacename> implementations
are defined like any other object (or bean) in the Spring Framework IoC
container. This benefit alone makes Spring Framework transactions a
worthwhile abstraction even when you work with JTA. Transactional code can
be tested much more easily than if it used JTA directly.</para>
<para>Again in keeping with Spring's philosophy, the
<exceptionname>TransactionException</exceptionname> that can be thrown by
any of the <interfacename>PlatformTransactionManager</interfacename>
interface's methods is <emphasis>unchecked</emphasis> (that is, it extends
the <exceptionname>java.lang.RuntimeException</exceptionname> class).
Transaction infrastructure failures are almost invariably fatal. In rare
cases where application code can actually recover from a transaction
failure, the application developer can still choose to catch and handle
<exceptionname>TransactionException</exceptionname>. The salient point is
that developers are not <emphasis>forced</emphasis> to do so.</para>
<para>The <methodname>getTransaction(..)</methodname> method returns a
<interfacename>TransactionStatus</interfacename> object, depending on a
<interfacename>TransactionDefinition</interfacename> parameter. The
returned <interfacename>TransactionStatus</interfacename> might represent
a new transaction, or can represent an existing transaction if a matching
transaction exists in the current call stack. The implication in this
latter case is that, as with Java EE transaction contexts, a
<interfacename>TransactionStatus</interfacename> is associated with a
<emphasis role="bold">thread</emphasis> of execution.<!--Previous sentences were difficult to follow because of all the parenthetical phrases.Revise if necessary. TR: OK AS IS--></para>
<para>The <interfacename>TransactionDefinition</interfacename> interface
specifies:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Isolation</emphasis>: The degree to which
this transaction is isolated from the work of other transactions. For
example, can this transaction see uncommitted writes from other
transactions?</para>
</listitem>
<listitem>
<para><emphasis role="bold">Propagation</emphasis>: Typically, all
code executed within a transaction scope will run in that transaction.
However, you have the option of specifying the behavior in the event
that a transactional method is executed when a transaction context
already exists. <!--Correct to say you have options? A human has to specify what the behavior will be, right? TR: REVISED, PLS REVIEW-->For
example, code can continue running in the existing transaction (the
common case); or the existing transaction can be suspended and a new
transaction created. <emphasis>Spring offers all of the transaction
propagation options familiar from EJB CMT</emphasis>. To read about
the semantics of transaction propagation in Spring, see <xref
linkend="tx-propagation" />.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Timeout</emphasis>: How long this
transaction runs before timing out and being rolled back automatically
by the underlying transaction infrastructure.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Read-only status</emphasis>: A read-only
transaction can be used when your code reads but does not modify data.
Read-only transactions can be a useful optimization in some cases,
such as when you are using Hibernate.</para>
<!--describes status but we could say 'reads but does not modify' I added that it describes status. OK? Elaborate on purpose?
TR:REVISED, PLS REVIEW-->
</listitem>
</itemizedlist>
<para>These settings reflect standard transactional concepts. If
necessary, refer to resources that discuss transaction isolation levels
and other core transaction concepts. Understanding these concepts is
essential to using the Spring Framework or any transaction management
solution.</para>
<para>The <interfacename>TransactionStatus</interfacename> interface
provides a simple way for transactional code to control transaction
execution and query transaction status. The concepts should be familiar,
as they are common to all transaction APIs:</para>
<programlisting language="java">public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}</programlisting>
<para>Regardless of whether you opt for declarative or programmatic
transaction management in Spring, defining the correct
<interfacename>PlatformTransactionManager</interfacename> implementation
is absolutely essential. You typically define this implementation through
dependency injection.</para>
<!--Do you need a link to an explanation of DI?
TR: OK AS IS - at this point in the text, I don't think you would need that
-->
<para><interfacename>PlatformTransactionManager</interfacename>
implementations normally require knowledge of the environment in which
they work: JDBC, JTA, Hibernate, and so on. The following examples show
how you can define a local
<interfacename>PlatformTransactionManager</interfacename> implementation.
(This example works with plain JDBC.)</para>
<para>You define a JDBC <interfacename>DataSource</interfacename></para>
<programlisting language="xml"><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean></programlisting>
<para>The related <interfacename>PlatformTransactionManager</interfacename>
bean definition will then have a reference to the
<interfacename>DataSource</interfacename> definition. It will look like this:</para>
<programlisting language="xml"><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean></programlisting>
<para>If you use JTA in a Java EE container then you use a container
<interfacename>DataSource</interfacename>, obtained through JNDI, in
conjunction with Spring's <classname>JtaTransactionManager</classname>.
This is what the JTA and JNDI lookup version would look like:</para>
<!--Indicate what the following example demonstrates.What is its purpose? TR: REVISED, PLS REVIEW-->
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<lineannotation><!-- other <literal><bean/></literal> definitions here --></lineannotation>
</beans></programlisting>
<para>The <classname>JtaTransactionManager</classname> does not need to
know about the <interfacename>DataSource</interfacename>, or any other
specific resources, because it uses the container's global transaction
management infrastructure.</para>
<note>
<para>The above definition of the <literal>dataSource</literal> bean
uses the <literal><jndi-lookup/></literal> tag from the
<literal>jee</literal> namespace. For more information on schema-based
configuration, see <xref linkend="xsd-config" />, and for more
information on the <literal><jee/></literal> tags see the section
entitled <xref linkend="xsd-config-body-schemas-jee" />.</para>
</note>
<para>You can also use Hibernate local transactions easily, as shown in
the following examples. In this case, you need to define a Hibernate
<classname>LocalSessionFactoryBean</classname>, which your application
code will use to obtain Hibernate <interfacename>Session</interfacename>
instances.</para>
<para>The <interfacename>DataSource</interfacename> bean definition will
be similar to the local JDBC example shown previously and thus is not
shown in the following example.</para>
<!-- TR: added the following clarification rather than embed it in the text above-->
<note>
<para>If the <interfacename>DataSource</interfacename>, used by any
non-JTA transaction manager, is looked up via JNDI and managed by a Java
EE container, then it should be non-transactional because the Spring
Framework, rather than the Java EE container, will manage the
transactions.</para>
</note>
<para>The <literal>txManager</literal> bean in this case is of the
<classname>HibernateTransactionManager</classname> type. In the same way
as the <classname>DataSourceTransactionManager</classname> needs a
reference to the <interfacename>DataSource</interfacename>, the
<classname>HibernateTransactionManager</classname> needs a reference to
the <interfacename>SessionFactory</interfacename>.</para>
<programlisting language="xml"><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean></programlisting>
<para>If you are using Hibernate and Java EE container-managed JTA
transactions, then you should simply use the same
<classname>JtaTransactionManager</classname> as in the previous JTA
example for JDBC.<!--Use it to do what? Below, this *what* is identical to JTA config
TR: REVISED, PLS REVIEW - I clarified this a bit
--></para>
<programlisting language="xml"><bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/></programlisting>
<note>
<para>If you use JTA , then your transaction manager definition will
look the same regardless of what data access technology you use, be it
JDBC, Hibernate JPA or any other supported technology. This is due to
the fact that JTA transactions are global transactions, which can enlist
any transactional resource.</para>
</note>
<para>In all these cases, application code does not need to change. You
can change how transactions are managed merely by changing configuration,
even if that change means moving from local to global transactions or vice
versa.</para>
</section>
<section id="tx-resource-synchronization">
<title>Synchronizing resources with transactions</title>
<para>It should now be clear how you create different transaction
managers, and how they are linked to related resources that need to be
synchronized to transactions (for example
<classname>DataSourceTransactionManager</classname> to a JDBC
<interfacename>DataSource</interfacename>,
<classname>HibernateTransactionManager</classname> to a Hibernate
<interfacename>SessionFactory</interfacename>, and so forth). This section
describes how the application code, directly or indirectly using a
persistence API such as JDBC, Hibernate, or JDO, ensures that these
resources are created, reused, and cleaned up properly. The section also
discusses how transaction synchronization is triggered (optionally)
through the relevant
<interfacename>PlatformTransactionManager</interfacename>.<!--I broke into two sentences. Last part of sentence unclear,revise to say what triggers tx synch. Revise sentences if necessray. TR: OK--></para>
<section id="tx-resource-synchronization-high">
<title>High-level synchronization approach</title>
<para>The preferred approach is to use Spring's highest level template
based persistence integration APIs or to use native ORM APIs with
transaction- aware factory beans or proxies for managing the native
resource factories. These transaction-aware solutions internally handle
resource creation and reuse, cleanup, optional transaction
synchronization of the resources, and exception mapping. Thus user data
access code does not have to address these tasks, but can be focused
purely on non-boilerplate persistence logic. Generally, you use the
native ORM API or take a <emphasis>template</emphasis> approach for JDBC
access by using the <classname>JdbcTemplate</classname>. These solutions
are detailed in subsequent chapters of this reference documentation.<!--If this approach is preferred, why not give examples here as you do with less desirable approaches? At least provide--><!--x-refs? Also is it correct to refer to APIs, then give classes as examples? Should this be reworded?
TR: REVISED, PLS REVIEW - I re-wrote this to match the current preferred approaches--></para>
</section>
<section id="tx-resource-synchronization-low">
<title>Low-level synchronization approach</title>
<para>Classes such as <classname>DataSourceUtils</classname> (for JDBC),
<classname>EntityManagerFactoryUtils</classname> (for JPA),
<classname>SessionFactoryUtils</classname> (for Hibernate),
<classname>PersistenceManagerFactoryUtils</classname> (for JDO), and so
on exist at a lower level. When you want the application code to deal
directly with the resource types of the native persistence APIs, you use
these classes to ensure that proper Spring Framework-managed instances
are obtained, transactions are (optionally) synchronized, and exceptions
that occur in the process are properly mapped to a consistent
API.</para>
<para>For example, in the case of JDBC, instead of the traditional JDBC
approach of calling the <literal>getConnection()</literal> method on the
<interfacename>DataSource</interfacename>, you instead use Spring's
<classname>org.springframework.jdbc.datasource.DataSourceUtils</classname>
class as follows:</para>
<programlisting language="java">Connection conn = DataSourceUtils.getConnection(dataSource);</programlisting>
<para>If an existing transaction already has a connection synchronized
(linked) to it, that instance is returned. Otherwise, the method call
triggers the creation of a new connection, which is (optionally)
synchronized to any existing transaction, and made available for
subsequent reuse in that same transaction. As mentioned, any
<exceptionname>SQLException</exceptionname> is wrapped in a Spring
Framework
<exceptionname>CannotGetJdbcConnectionException</exceptionname>, one of
the Spring Framework's hierarchy of unchecked DataAccessExceptions. This
approach gives you more information than can be obtained easily from the
<exceptionname>SQLException</exceptionname>, and ensures portability
across databases, even across different persistence technologies.</para>
<para>This approach also works without Spring transaction management
(transaction synchronization is optional), so you can use it whether or
not you are using Spring for transaction management.</para>
<para>Of course, once you have used Spring's JDBC support, JPA support
or Hibernate support, you will generally prefer not to use
<classname>DataSourceUtils</classname> or the other helper classes,
because you will be much happier working through the Spring abstraction
than directly with the relevant APIs. For example, if you use the Spring
<classname>JdbcTemplate</classname> or <literal>jdbc.object</literal>
package to simplify your use of JDBC, correct connection retrieval
occurs behind the scenes and you won't need to write any special
code.</para>
<!--I don't understand this. Why tell them to use DataSourceUtils and then say you will prefer Spring abstraction?
Why not give example of using Spring abstraction?
TR: OK AS IS - it's not the prefered way, but we need to cover this if someine decideds to use it-->
</section>
<section id="tx-resource-synchronization-tadsp">
<title><classname>TransactionAwareDataSourceProxy</classname></title>
<para>At the very lowest level exists the
<classname>TransactionAwareDataSourceProxy</classname> class. This is a
proxy for a target <interfacename>DataSource</interfacename>, which
wraps the target <interfacename>DataSource</interfacename> to add
awareness of Spring-managed transactions. In this respect, it is similar
to a transactional JNDI <interfacename>DataSource</interfacename> as
provided by a Java EE server.<!--What is the purpose of TransactionAwareDataSourceProxy, do you use it instead of 4.2 or 4.1 approaches or in addition to?
TR: OK AS IS - it's and additional tool, rarely used, but needs to be documented--></para>
<para>It should almost never be necessary or desirable to use this
class, except when existing code must be called and passed a standard
JDBC <interfacename>DataSource</interfacename> interface implementation.
In that case, it is possible that this code is usable, but participating
in Spring managed transactions. It is preferable to write your new code
by using the higher level abstractions mentioned above.</para>
</section>
</section>
<section id="transaction-declarative">
<title>Declarative transaction management</title>
<note>
<para>Most Spring Framework users choose declarative transaction
management. This option has the least impact on application code, and
hence is most consistent with the ideals of a
<emphasis>non-invasive</emphasis> lightweight container.</para>
</note>
<para>The Spring Framework's declarative transaction management is made
possible with Spring aspect-oriented programming (AOP), although, as the
transactional aspects code comes with the Spring Framework distribution
and may be used in a boilerplate fashion, AOP concepts do not generally
have to be understood to make effective use of this code.</para>
<para>The Spring Framework's declarative transaction management is similar
to EJB CMT in that you can specify transaction behavior (or lack of it)
down to individual method level. It is possible to make a
<methodname>setRollbackOnly()</methodname> call within a transaction
context if necessary. The differences between the two types of transaction
management are:</para>
<itemizedlist>
<listitem>
<para>Unlike EJB CMT, which is tied to JTA, the Spring Framework's
declarative transaction management works in any environment. It can
work with JTA transactions or local transactions using JDBC, JPA,
Hibernate or JDO by simply adjusting the configuration files.<!--Indicate what kind of config changes? Changes to what
TR: REVISED, PLS REVIEW - rewrote this to hoefully make it more clear--></para>
</listitem>
<listitem>
<para>You can apply the Spring Framework declarative transaction
management to any class, not merely special classes such as
EJBs.</para>
</listitem>
<listitem>
<para>The Spring Framework offers declarative <link
linkend="transaction-declarative-rolling-back"><emphasis>rollback
rules</emphasis>, </link>a feature with no EJB equivalent. Both
programmatic and declarative support for rollback rules is
provided.</para>
</listitem>
<listitem>
<para>The Spring Framework enables you to customize transactional
behavior, by using AOP. For example, you can insert custom behavior in
the case of transaction rollback. You can also add arbitrary advice,
along with the transactional advice. With EJB CMT, you cannot influence
the container's transaction management except with
<methodname>setRollbackOnly()</methodname>.</para>
</listitem>
<listitem>
<para>The Spring Framework does not support propagation of transaction
contexts across remote calls, as do high-end application servers. If
you need this feature, we recommend that you use EJB. However,
consider carefully before using such a feature, because normally, one
does not want transactions to span remote calls.</para>
</listitem>
</itemizedlist>
<sidebar>
<title>Where is
<classname>TransactionProxyFactoryBean</classname>?</title>
<para>Declarative transaction configuration in versions of Spring 2.0
and above differs considerably from previous versions of Spring. The
main difference is that there is no longer any need to configure
<classname>TransactionProxyFactoryBean</classname> beans.</para>
<para>The pre-Spring 2.0 configuration style is still 100% valid
configuration; think of the new <literal><tx:tags/></literal> as
simply defining <classname>TransactionProxyFactoryBean</classname> beans
on your behalf.</para>
</sidebar>
<para>The concept of rollback rules is important: they enable you to
specify which exceptions (and throwables) <!--If no difference between exceptions and throwables, delete throwables. TR: OK AS IS-->should
cause automatic rollback. You specify this declaratively, in
configuration, not in Java code. So, although you can still call
<methodname>setRollbackOnly()</methodname>on the
<interfacename>TransactionStatus</interfacename> object to roll back the
current transaction back, most often you can specify a rule that
<exceptionname>MyApplicationException</exceptionname> must always result
in rollback. The significant advantage to this option is that business
objects do not depend on the transaction infrastructure. For example, they
typically do not need to import Spring transaction APIs or other Spring
APIs.</para>
<para>Although EJB container default behavior automatically rolls back the
transaction on a <emphasis>system exception</emphasis> (usually a runtime
exception), EJB CMT does not roll back the transaction automatically on an
<emphasis>application exception</emphasis> (that is, a checked exception
other than <exceptionname>java.rmi.RemoteException</exceptionname>). While
the Spring default behavior for declarative transaction management follows
EJB convention (roll back is automatic only on unchecked exceptions), it
is often useful to customize this behavior.</para>
<!--customize this so that what happens? TR: OK AS IS - i think - the option is to provide alternate rules for when a transaction
would be rolled back, not necessarily following the EJB rules-->
<section id="tx-decl-explained">
<title>Understanding the Spring Framework's declarative transaction
implementation</title>
<para>It is not sufficient to tell you simply to annotate your classes
with the <interfacename>@Transactional</interfacename> annotation, add
the line (<literal><tx:annotation-driven/></literal>) to your
configuration, and then expect you to understand how it all works. This
section explains the inner workings of the Spring Framework's
declarative transaction infrastructure in the event of
transaction-related issues.</para>
<para>The most important concepts to grasp with regard to the Spring
Framework's declarative transaction support are that this support is
enabled <link linkend="aop-understanding-aop-proxies"><emphasis>via AOP
proxies</emphasis></link>, and that the transactional advice is driven
by <emphasis>metadata</emphasis> (currently XML- or annotation-based).
The combination of AOP with transactional metadata yields an AOP proxy
that uses a <classname>TransactionInterceptor</classname> in conjunction
with an appropriate <classname>PlatformTransactionManager</classname>
implementation to drive transactions <emphasis>around method
invocations</emphasis>.</para>
<note>
<para>Spring AOP is covered in <xref linkend="aop" />.</para>
</note>
<para>Conceptually, calling a method on a transactional proxy looks like
this...</para>
<!--I don't see this image in src file or in pdf. Maybe it was added to src after pdf was created?
TR: OK AS IS. images don't show up in the editor, but they do show up in the generated docs-->
<para><mediaobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/tx.png" format="PNG"
width="400"/>
</imageobject>
<imageobject role="html">
<imagedata align="center" fileref="images/tx.png" format="PNG" />
</imageobject>
</mediaobject></para>
</section>
<section id="transaction-declarative-first-example">
<title>Example of declarative transaction implementation</title>
<para>Consider the following interface, and its attendant
implementation. This example uses <classname>Foo</classname> and
<classname>Bar</classname> classes as placeholders so that you can
concentrate on the transaction usage without focusing on a particular
domain model. For the purposes of this example, the fact that the
<classname>DefaultFooService</classname> class throws
<exceptionname>UnsupportedOperationException</exceptionname> instances
in the body of each implemented method is good; it allows you to see
transactions created and then rolled back in response to the
<exceptionname>UnsupportedOperationException</exceptionname> instance.
</para>
<programlisting language="java"><lineannotation>// the service interface that we want to make transactional</lineannotation>
package x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}</programlisting>
<programlisting language="java"><lineannotation>// an implementation of the above interface</lineannotation>
package x.y.service;
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}</programlisting>
<para>Assume that the first two methods of the
<interfacename>FooService</interfacename> interface<literal>,
getFoo(String)</literal> and <literal>getFoo(String, String),
</literal>must execute in the context of a transaction with read-only
semantics, and that the other methods<literal>,insertFoo(Foo)</literal>
and <literal>updateFoo(Foo),</literal> must execute in the context of a
transaction with read-write semantics. The following configuration is
explained in detail in the next few paragraphs.</para>
<programlisting language="xml"><lineannotation><!-- from the file <literal>'context.xml'</literal> --></lineannotation>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
<lineannotation><emphasis role="bold">xmlns:tx="http://www.springframework.org/schema/tx"</emphasis></lineannotation>
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
<lineannotation><emphasis role="bold">http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd</emphasis></lineannotation>
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<lineannotation><!-- this is the service object that we want to make transactional --></lineannotation>
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<lineannotation><!-- the transactional advice (what 'happens'; see the <literal><aop:advisor/></literal> bean below) --></lineannotation>
<tx:advice id="txAdvice" transaction-manager="txManager">
<lineannotation><!-- the transactional semantics... --></lineannotation>
<tx:attributes>
<lineannotation><!-- all methods starting with <literal>'get'</literal> are read-only --></lineannotation>
<tx:method name="get*" read-only="true"/>
<lineannotation><!-- other methods use the default transaction settings (see below) --></lineannotation>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<lineannotation><!-- ensure that the above transactional advice runs for any execution
of an operation defined by the <interfacename>FooService</interfacename> interface --></lineannotation>
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<lineannotation><!-- don't forget the <interfacename>DataSource</interfacename> --></lineannotation>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<lineannotation><!-- similarly, don't forget the <interfacename>PlatformTransactionManager</interfacename> --></lineannotation>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<lineannotation><!-- other <literal><bean/></literal> definitions here --></lineannotation>
</beans></programlisting>
<para>Examine the preceding configuration. You want to make a service
object, the <literal>fooService</literal> bean, transactional. The
transaction semantics to apply are encapsulated in the
<literal><tx:advice/></literal> definition. The
<literal><tx:advice/></literal> definition reads as
<quote><emphasis>... all methods on starting with
<literal>'get'</literal> are to execute in the context of a read-only
transaction, and all other methods are to execute with the default
transaction semantics</emphasis></quote>. The
<literal>transaction-manager</literal> attribute of the
<literal><tx:advice/></literal> tag is set to the name of the
<interfacename>PlatformTransactionManager</interfacename> bean that is
going to <emphasis>drive</emphasis> the transactions, in this case, the
<literal>txManager</literal> bean.</para>
<tip>
<para>You can omit the <literal>transaction-manager</literal>
attribute in the transactional advice
(<literal><tx:advice/></literal>) if the bean name of the
<interfacename>PlatformTransactionManager</interfacename> that you
want to wire in has the name <literal>transactionManager</literal>. If
the <interfacename>PlatformTransactionManager</interfacename> bean
that you want to wire in has any other name, then you must use the
<literal>transaction-manager</literal> attribute explicitly, as in the
preceding example.</para>
</tip>
<para>The <literal><aop:config/></literal> definition ensures that
the transactional advice defined by the <literal>txAdvice</literal> bean
executes at the appropriate points in the program. First you define a
pointcut that matches the execution of any operation defined in the
<interfacename>FooService</interfacename> interface
(<literal>fooServiceOperation</literal>). Then you associate the
pointcut with the <literal>txAdvice</literal> using an advisor. The
result indicates that at the execution of a
<literal>fooServiceOperation</literal>, the advice defined by
<literal>txAdvice</literal> will be run.</para>
<para>The expression defined within the
<literal><aop:pointcut/></literal> element is an AspectJ pointcut
expression; see <xref linkend="aop" /> for more details on pointcut
expressions in Spring 2.0.</para>
<para>A common requirement is to make an entire service layer
transactional. The best way to do this is simply to change the pointcut
expression to match any operation in your service layer. For
example:</para>
<programlisting language="xml"><aop:config>
<aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
</aop:config></programlisting>
<para><note>
<para><emphasis>In this example it is assumed that all your service
interfaces are defined in the <literal>x.y.service</literal>
package; see <xref linkend="aop" /> for more
details.</emphasis></para>
</note></para>
<para>Now that we've analyzed the configuration, you may be asking
yourself, <quote><emphasis>Okay... but what does all this configuration
actually do?</emphasis></quote>.</para>
<para>The above configuration will be used to create a transactional
proxy around the object that is created from the
<literal>fooService</literal> bean definition. <!--Clarify what you mean by around the object; do you mean associated with the object? Revise to clarify. Around is vague.
TR: OK AS IS - around is used a lot in AOP, so I think the audience will understand this usage-->The
proxy will be configured with the transactional advice, so that when an
appropriate method is invoked <emphasis>on the proxy</emphasis>, a
transaction is started, suspended, marked as read-only, and so on,
depending on the transaction configuration associated with that method.
Consider the following program that test drives the above
configuration:</para>
<programlisting language="java">public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
FooService fooService = (FooService) ctx.getBean("fooService");
fooService.insertFoo (new Foo());
}
}</programlisting>
<para>The output from running the preceding program will resemble the
following. (The Log4J output and the stack trace from the
UnsupportedOperationException thrown by the insertFoo(..) method of the
DefaultFooService class have been truncated for clarity.)</para>
<programlisting language="xml"> <lineannotation><emphasis role="bold"><!-- the Spring container is starting up... --></emphasis></lineannotation>
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
for bean 'fooService' with 0 common interceptors and 1 specific interceptors
<lineannotation><emphasis role="bold"><!-- the <classname>DefaultFooService</classname> is actually proxied --></emphasis></lineannotation>
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]
<lineannotation><emphasis role="bold"><!-- ... the <literal>insertFoo(..)</literal> method is now being invoked on the proxy --></emphasis></lineannotation>
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
<lineannotation><emphasis role="bold"><!-- the transactional advice kicks in here... --></emphasis></lineannotation>
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction
<lineannotation><emphasis role="bold"><!-- the <literal>insertFoo(..)</literal> method from <classname>DefaultFooService</classname> throws an exception... --></emphasis></lineannotation>
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should
rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo
due to throwable [java.lang.UnsupportedOperationException]
<lineannotation><emphasis role="bold"><!-- and the transaction is rolled back (by default, <exceptionname>RuntimeException</exceptionname> instances cause rollback) --></emphasis></lineannotation>
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource
Exception in thread "main" java.lang.UnsupportedOperationException
at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
<lineannotation><emphasis role="bold"><!-- AOP infrastructure stack trace elements removed for clarity --></emphasis></lineannotation>
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)</programlisting>
</section>
<section id="transaction-declarative-rolling-back">
<title>Rolling back a declarative transaction</title>
<para>The previous section outlined the basics of how to specify
transactional settings for classes, typically service layer classes,
declaratively in your application. This section describes how you can
control the rollback of transactions in a simple declarative
fashion.</para>
<para>The recommended way to indicate to the Spring Framework's
transaction infrastructure that a transaction's work is to be rolled
back is to throw an <exceptionname>Exception</exceptionname> from code
that is currently executing in the context of a transaction. The Spring
Framework's transaction infrastructure code will catch any unhandled
<exceptionname>Exception</exceptionname> as it bubbles up the call
stack, and make a determination whether to mark the transaction for
rollback.<!--I changed to *can be configured* because next sentence says it does not do this by default in all cases.
TR: REVISED, PLS REVIEW. I changed it to *in its default configuration*BT: I STILL DON'T GET IT. PRECEDING SENTENCE AND FOLLOWING --><!--SENTENCE SEEM CONTRADICTORY. TR: REVISED AGAIN, PLS REVIEW.--></para>
<para>In its default configuration, the Spring Framework's transaction
infrastructure code <emphasis>only</emphasis> marks a transaction for
rollback in the case of runtime, unchecked exceptions; that is, when the
thrown exception is an instance or subclass of
<exceptionname>RuntimeException</exceptionname>.
(<exceptionname>Error</exceptionname>s will also - by default - result
in a rollback). Checked exceptions that are thrown from a transactional
method do <emphasis>not</emphasis> result in rollback in the default
configuration.<!--I revised preceding because it says ONLY first case is rolled back by default, but then says Errors are also marked by default.
TR: OK AS IS. Errors aren't thrown by application code, only checked or unchecked exceptions are. So the Errors part is just clarifying that
if the underlying application server infrastructure throws an Error the transaction will be rolled back.--></para>
<para>You can configure exactly which