forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathorm.xml
More file actions
2055 lines (1704 loc) · 102 KB
/
orm.xml
File metadata and controls
2055 lines (1704 loc) · 102 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="orm">
<title>Object Relational Mapping (ORM) Data Access</title>
<section id="orm-introduction">
<title>Introduction to ORM with Spring</title>
<para>The Spring Framework supports integration
with Hibernate, Java Persistence API (JPA), Java Data Objects (JDO) and
iBATIS SQL Maps for resource management, data access object (DAO)
implementations, and transaction strategies. For example, for Hibernate
there is first-class support with several convenient IoC features that
address many typical Hibernate integration issues. You can configure
all of the supported features for O/R (object relational) mapping tools through
Dependency Injection. They can participate in Spring's resource
and transaction management, and they comply with Spring's generic
transaction and DAO exception hierarchies. The recommended integration
style is to code DAOs against plain Hibernate, JPA, and JDO APIs. The
older style of using Spring's DAO templates is no longer recommended;
however, coverage of this style can be found in the <xref
linkend="classic-spring-orm" /> in the appendices.</para>
<para>Spring adds significant enhancements to the ORM layer of your choice
when you create data access applications. You can leverage as much of the
integration support as you wish, and you should compare this integration
effort with the cost and risk of building a similar infrastructure
in-house. You can use much of the ORM support as you would a library,
regardless of technology, because everything is designed as a set of
reusable JavaBeans. ORM in a Spring IoC container facilitates
configuration and deployment. Thus most examples in this section show
configuration inside a Spring container.</para>
<para>Benefits of using the Spring Framework to create your ORM DAOs
include:</para>
<itemizedlist>
<listitem>
<para><emphasis>Easier testing.</emphasis> Spring's IoC approach makes
it easy to swap the implementations and configuration locations of
Hibernate <interfacename>SessionFactory</interfacename> instances,
JDBC <interfacename>DataSource</interfacename> instances, transaction
managers, and mapped object implementations (if needed). <!--I changed *mappes* to *mapped*; is that what you mean? Also, clarify whether *if needed* refers only to that or to the rest as well
TR: OK. Refers only to mapped object implementations-->This in turn makes it
much easier to test each piece of persistence-related code in
isolation.<!--deleted redundancy; sentence already refers to isolating each piece of code. TR: OK. moved isolation to the end--></para>
</listitem>
<listitem>
<para><emphasis>Common data access exceptions.</emphasis> Spring can
wrap exceptions from your ORM tool, converting them from proprietary
(potentially checked) exceptions to a common runtime
DataAccessException hierarchy. This feature allows you to handle most
persistence exceptions, which are non-recoverable, only in the
appropriate layers, without annoying boilerplate catches, throws, and
exception declarations. You can still trap and handle exceptions as
necessary. Remember that JDBC exceptions (including DB-specific
dialects) are also converted to the same hierarchy, meaning that you
can perform some operations with JDBC within a consistent programming
model.</para>
</listitem>
<listitem>
<para><emphasis>General resource management.</emphasis> Spring
application contexts can handle the location and configuration of
Hibernate <interfacename>SessionFactory</interfacename> instances, JPA
<interfacename>EntityManagerFactory</interfacename> instances, JDBC
<interfacename>DataSource</interfacename> instances, iBATIS SQL Maps
configuration objects, and other related resources. This makes these
values easy to manage and change. Spring offers efficient, easy, and
safe handling of persistence resources. For example, related code that
uses Hibernate generally needs to use the same Hibernate
<interfacename>Session</interfacename> to ensure efficiency and proper
transaction handling. Spring makes it easy to create and bind a
<interfacename>Session</interfacename> to the current thread
transparently, <!--This bullet and next refer to template wrapper class. Is this referring to using Spring DAO templates, whichis no longer recommend--><!--ed? If so, it's confusing to discuss it as an option. Sends a mixed message. If not, explain what you mean by *template* wrapper class.
TR: REVISED, PLS REVIEW. Good point, removed coverage of template wrapper.-->by
exposing a current <interfacename>Session</interfacename> through the
Hibernate <interfacename>SessionFactory</interfacename>. Thus Spring
solves many chronic problems of typical Hibernate usage, for any local
or JTA transaction environment.</para>
</listitem>
<listitem>
<para><emphasis>Integrated transaction management.</emphasis> You can
wrap your ORM code with a declarative, aspect-oriented programming
(AOP) style method interceptor either through the
<interfacename>@Transactional</interfacename> annotation or by
explicitly configuring the transaction AOP advice in an XML
configuration file. In both cases, transaction semantics and exception
handling (rollback, and so on) are handled for you. As discussed
below, in <!--Instead of *below*, provide link to section. TR: OK--><link
linkend="orm-resource-mngmnt">Resource and transaction
management</link>, you can also swap various transaction managers,
without affecting your ORM-related code. For example, you can swap
between local transactions and JTA, with the same full services (such
as declarative transactions) available in both scenarios.
Additionally, JDBC-related code can fully integrate transactionally
with the code you use to do ORM. This is useful for data access that
is not suitable for ORM, such as batch processing and BLOB streaming,
which still need <!--if both batch processing and BLOB streaming need to share common transactions w/ ORM, then change *needs* to *to need*. If --><!--it refers only to BLOB streaming, say *the latter of which still needs to share...* TR: OK. Chnaged to *to need*-->to
share common transactions with ORM operations.</para>
</listitem>
</itemizedlist>
<para><!--The PetClinic sample in the Spring distribution offers alternative DAO implementations and application context configurations for JDBC,
Hibernate, and JPA. PetClinic is a working sample application that illustrates the use of Hibernate and JPA in a Spring web application.
It also leverages declarative transaction demarcation with different transaction strategies.
Beyond the samples shipped with Spring, vendors provide a variety of Spring-based ORM samples. --><!--Name vendors, link to them? TR: WILL ADDRESS LATER. We need to point to the current samples which aren't completed yet. --><emphasis>TODO:
provide links to current samples</emphasis></para>
</section>
<section id="orm-general">
<title>General ORM integration considerations</title>
<para>This section highlights considerations that apply to all ORM
technologies. The <xref linkend="orm-hibernate" /> section provides more
details and also show these features and configurations in a concrete
context.</para>
<para>The major goal of Spring's ORM integration is clear application
layering, with any data access and transaction technology, and for loose
coupling of application objects. No more business service dependencies on
the data access or transaction strategy, no more hard-coded resource
lookups, no more hard-to-replace singletons, no more custom service
registries. One simple and consistent approach to wiring up application
objects, keeping them as reusable and free from container dependencies as
possible. All the individual data access features are usable on their own
but integrate nicely with Spring's application context concept, providing
XML-based configuration and cross-referencing of plain JavaBean instances
that need not be Spring-aware. In a typical Spring application, many
important objects are JavaBeans: data access templates, data access
objects, transaction managers, business services that use the data access
objects and transaction managers, web view resolvers, web controllers that
use the business services,and so on.</para>
<section id="orm-resource-mngmnt">
<title>Resource and transaction management</title>
<para>Typical business applications are cluttered with repetitive
resource management code. Many projects try to invent their own
solutions, sometimes sacrificing proper handling of failures for
programming convenience. Spring advocates simple solutions for proper
resource handling, namely IoC through templating<!--same question as before re templates. Does preceding refer to Spring templates that in beginning you say you no longer recommend?
TR: OK AS IS. The template for JDBC is still recommended--> in the case of
JDBC and applying AOP interceptors for the ORM technologies.</para>
<para>The infrastructure provides proper resource handling and
appropriate conversion of specific API exceptions to an unchecked
infrastructure exception hierarchy. <!--What do you mean by *cares for*? I substituted *provides*. Should it be *implements*? TR: OK-->Spring
introduces a DAO exception hierarchy, applicable to any data access
strategy. For direct JDBC, the <classname>JdbcTemplate</classname> class
mentioned in a previous section provides connection handling and proper
conversion of <classname>SQLException</classname> to the
<classname>DataAccessException</classname> hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. For ORM technologies, see the next section for how to get the
same exception translation benefits.</para>
<para>When it comes to transaction management, the
<classname>JdbcTemplate</classname> class hooks in to the Spring
transaction support and supports both JTA and JDBC transactions, through
respective Spring transaction managers. For the supported ORM
technologies Spring offers Hibernate, JPA and JDO support through the
Hibernate, JPA, and JDO transaction managers as well as JTA support. For
details on transaction support, see the <xref linkend="transaction" />
chapter.</para>
</section>
<section id="orm-exception-translation">
<title>Exception translation</title>
<para>When you use Hibernate, JPA, or JDO in a DAO, you must decide how
to handle the persistence technology's native exception classes. The DAO
throws a subclass of a <classname>HibernateException</classname>,
<classname>PersistenceException</classname> or
<interfacename>JDOException</interfacename> depending on the technology.
These exceptions are all run-time exceptions and do not have to be
declared or caught. You may also have to deal with
<classname>IllegalArgumentException</classname> and
<classname>IllegalStateException</classname>. This means that callers
can only treat exceptions as generally fatal, unless they want to depend
on the persistence technology's own exception structure. Catching
specific causes such as an optimistic locking failure is not possible
without tying the caller to the implementation strategy. This trade off
might be acceptable to applications that are strongly ORM-based and/or
do not need any special exception treatment. However, Spring enables
exception translation to be applied transparently through the
<interfacename>@Repository</interfacename> annotation:</para>
<programlisting language="java">@Repository
public class ProductDaoImpl implements ProductDao {
<lineannotation>// class body here...</lineannotation>
}</programlisting>
<programlisting language="xml"><beans>
<lineannotation><!-- <classname>Exception</classname> translation bean post processor --></lineannotation>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans></programlisting>
<para>The postprocessor automatically looks for all exception
translators (implementations of the
<interfacename>PersistenceExceptionTranslator</interfacename> interface)
and advises all beans marked with the
<interfacename>@Repository</interfacename> annotation so that the
discovered translators can intercept and apply the appropriate
translation on the thrown exceptions.</para>
<para>In summary: you can implement DAOs based on the plain persistence
technology's API and annotations, while still benefiting from
Spring-managed transactions, dependency injection, and transparent
exception conversion (if desired) to Spring's custom exception
hierarchies.</para>
</section>
</section>
<section id="orm-hibernate">
<title>Hibernate</title>
<para>We will start with a coverage of <ulink
url="http://www.hibernate.org/">Hibernate 3</ulink> in a Spring
environment, using it to demonstrate the approach that Spring takes
towards integrating O/R mappers. This section will cover many issues in
detail and show different variations of DAO implementations and
transaction demarcation. Most of these patterns can be directly translated
to all other supported ORM tools. The following sections in this chapter
will then cover the other ORM technologies, showing briefer examples
there.</para>
<para><note><para>As of Spring 3.0, Spring requires Hibernate 3.2 or later.</para></note></para>
<section id="orm-session-factory-setup">
<title><interfacename>SessionFactory</interfacename> setup in a Spring
container</title>
<para>To avoid tying application objects to hard-coded resource lookups,
you can define resources such as a JDBC
<interfacename>DataSource</interfacename> or a Hibernate
<interfacename>SessionFactory</interfacename> as beans in the Spring
container. Application objects that need to access resources receive
references to such predefined instances through bean references, as
illustrated in the DAO definition in the next section.</para>
<para>The following excerpt from an XML application context definition
shows how to set up a JDBC <classname>DataSource</classname> and a
Hibernate <interfacename>SessionFactory</interfacename> on top of
it:</para>
<programlisting language="xml"><beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
</beans></programlisting>
<para>Switching from a local Jakarta Commons DBCP
<classname>BasicDataSource</classname> to a JNDI-located
<interfacename>DataSource</interfacename> (usually managed by an
application server) is just a matter of configuration:</para>
<programlisting language="xml"><beans>
<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>
</beans></programlisting>
<para>You can also access a JNDI-located
<interfacename>SessionFactory</interfacename>, using Spring's
<classname>JndiObjectFactoryBean</classname> /
<literal><jee:jndi-lookup></literal> to retrieve and expose it.
However, that is typically not common outside of an EJB context.</para>
</section>
<section id="orm-hibernate-straight">
<title>Implementing DAOs based on plain Hibernate 3 API</title>
<para>Hibernate 3 has a feature called contextual sessions, wherein
Hibernate itself manages one current
<interfacename>Session</interfacename> per transaction. This is roughly
equivalent to Spring's synchronization of one Hibernate
<interfacename>Session</interfacename> per transaction. A corresponding
DAO implementation resembles the following example, based on the plain
Hibernate API:</para>
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Collection loadProductsByCategory(String category) {
return this.sessionFactory.getCurrentSession()
.createQuery("from test.Product product where product.category=?")
.setParameter(0, category)
.list();
}
}</programlisting>
<para>This style is similar to that of the Hibernate reference
documentation and examples, except for holding the
<interfacename>SessionFactory</interfacename> in an instance variable.
We strongly recommend such an instance-based setup over the old-school
<literal>static</literal> <classname>HibernateUtil</classname> class
from Hibernate's CaveatEmptor sample application. (In general, do not
keep any resources in <literal>static</literal> variables unless
<emphasis>absolutely</emphasis> necessary.)</para>
<para>The above DAO follows the dependency injection pattern: it fits
nicely into a Spring IoC container, just as it would if coded against
Spring's <classname>HibernateTemplate</classname>. Of course, such a DAO
can also be set up in plain Java (for example, in unit tests). Simply
instantiate it and call <methodname>setSessionFactory(..)</methodname>
with the desired factory reference. As a Spring bean definition, the DAO
would resemble the following:</para>
<programlisting language="xml"><beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
</beans></programlisting>
<para>The main advantage of this DAO style is that it depends on
Hibernate API only; no import of any Spring class is required. This is
of course appealing from a non-invasiveness perspective, and will no
doubt feel more natural to Hibernate developers.</para>
<para>However, the DAO throws plain
<classname>HibernateException</classname> (which is unchecked, so does
not have to be declared or caught), which means that callers can only
treat exceptions as generally fatal - unless they want to depend on
Hibernate's own exception hierarchy. Catching specific causes such as an
optimistic locking failure is not possible without tying the caller to
the implementation strategy. This trade off might be acceptable to
applications that are strongly Hibernate-based and/or do not need any
special exception treatment.</para>
<para>Fortunately, Spring's
<classname>LocalSessionFactoryBean</classname> supports Hibernate's
<methodname>SessionFactory.getCurrentSession()</methodname> method for
any Spring transaction strategy, returning the current Spring-managed
transactional <interfacename>Session</interfacename> even with
<classname>HibernateTransactionManager</classname>. Of course, the
standard behavior of that method remains the return of the current
<interfacename>Session</interfacename> associated with the ongoing JTA
transaction, if any. This behavior applies regardless of whether you are
using Spring's <classname>JtaTransactionManager</classname>, EJB
container managed transactions (CMTs), or JTA.</para>
<para>In summary: you can implement DAOs based on the plain Hibernate 3
API, while still being able to participate in Spring-managed
transactions.</para>
</section>
<section id="orm-hibernate-tx-declarative">
<title>Declarative transaction demarcation</title>
<para>We recommend that you use Spring's declarative transaction
support, which enables you to replace explicit transaction demarcation
API calls in your Java code with an AOP transaction interceptor. This
transaction interceptor can be configured in a Spring container using
either Java annotations or XML.<!--Reword last part of preceding sentence to clarify *what* is *using Java annotations or XML*. Are you using Java annotations or XML to replace--><!--explicit transaction demarcation API calls, etc. OR are you saying the Spring container is using these?
TR: REVISED, PLS REVIEW.-->This declarative transaction capability allows you
to keep business services free of repetitive transaction demarcation
code and to focus on adding business logic, which is the real value of
your application.</para>
<note>
<para>Prior to continuing, you are <emphasis>strongly</emphasis>
encouraged to read <xref linkend="transaction-declarative" /> if you
have not done so.</para>
</note>
<para>Furthermore, transaction semantics like propagation behavior and
isolation level can be changed in a configuration file and do not affect
the business service implementations.<!--give context to example; what is it showing, what is its purpose? TR: REVISED, PLS REVIEW. Added some context.--></para>
<para>The following example shows how you can configure an AOP
transaction interceptor, using XML, for a simple service class:</para>
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<lineannotation><!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --></lineannotation>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans></programlisting>
<para>This is the service class that is advised:</para>
<programlisting language="java">public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
<lineannotation>// notice the absence of transaction demarcation code in this method</lineannotation>
<lineannotation>// Spring's declarative transaction infrastructure will be demarcating</lineannotation>
<lineannotation>// transactions on your behalf </lineannotation>
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDao.loadProductsByCategory(category);
<lineannotation>// ...</lineannotation>
}
}</programlisting>
<para>We also show an attribute-support based configuration, in the
following example. <!--I added *in the following example*; is this correct? Relate example below to the one that follows it. TR: OK-->You
annotate the service layer with @Transactional annotations and instruct
the Spring container to find these annotations and provide transactional
semantics for these annotated methods.</para>
<programlisting language="java">public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
@Transactional
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDao.loadProductsByCategory(category);
<lineannotation>// ...</lineannotation>
}
@Transactional(readOnly = true)
public List<Product> findAllProducts() {
return this.productDao.findAllProducts();
}
}</programlisting>
<para>As you can see from the following configuration example, the
configuration is much simplified, compared to the XML example above,
while still providing the same functionality driven by the annotations
in the service layer code. All you need to provide is the
TransactionManager implementation and a "<tx:annotation-driven/>"
entry.<!--What does preceding example show, what's its relation to this example? TR: REVISED, PLS REVIEW.--></para>
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<lineannotation><!-- <interfacename>SessionFactory</interfacename>, <interfacename>DataSource</interfacename>, etc. omitted --></lineannotation>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans></programlisting>
</section>
<section id="orm-hibernate-tx-programmatic">
<title>Programmatic transaction demarcation</title>
<para>You can demarcate transactions in a higher level of the
application, on top of such lower-level data access services spanning
any number of operations. Nor do restrictions exist on the
implementation of the surrounding business service; it just needs a
Spring <classname>PlatformTransactionManager</classname>. Again, the
latter can come from anywhere, but preferably as a bean reference
through a <methodname>setTransactionManager(..)</methodname> method,
just as the <classname>productDAO</classname> should be set by a
<methodname>setProductDao(..)</methodname> method. The following
snippets show a transaction manager and a business service definition in
a Spring application context, and an example for a business method
implementation:</para>
<programlisting language="xml"><beans>
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="transactionManager" ref="myTxManager"/>
<property name="productDao" ref="myProductDao"/>
</bean>
</beans></programlisting>
<programlisting language="java">public class ProductServiceImpl implements ProductService {
private TransactionTemplate transactionTemplate;
private ProductDao productDao;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public void increasePriceOfAllProductsInCategory(final String category) {
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
List productsToChange = this.productDao.loadProductsByCategory(category);
<lineannotation>// do the price increase...</lineannotation>
}
}
);
}
}</programlisting>
<para>Spring's <classname>TransactionInterceptor</classname> allows any
checked application exception to be thrown with the callback code, while
<classname>TransactionTemplate</classname> is restricted to unchecked
exceptions within the callback.
<classname>TransactionTemplate</classname> triggers a rollback in case
of an unchecked application exception, or if the transaction is marked
rollback-only by the application (via
<classname>TransactionStatus</classname>).
<classname>TransactionInterceptor</classname> behaves the same way by
default but allows configurable rollback policies per method.</para>
</section>
<section id="orm-hibernate-tx-strategies">
<title>Transaction management strategies</title>
<para>Both <classname>TransactionTemplate</classname> and
<classname>TransactionInterceptor</classname> delegate the actual
transaction handling to a
<classname>PlatformTransactionManager</classname> instance, which can be
a <classname>HibernateTransactionManager</classname> (for a single
Hibernate <interfacename>SessionFactory</interfacename>, using a
<classname>ThreadLocal</classname>
<interfacename>Session</interfacename> under the hood) or a
<classname>JtaTransactionManager</classname> (delegating to the JTA
subsystem of the container) for Hibernate applications. You can even use
a custom <classname>PlatformTransactionManager</classname>
implementation. Switching from native Hibernate transaction management
to JTA, such as when facing distributed transaction requirements for
certain deployments of your application, is just a matter of
configuration. Simply replace the Hibernate transaction manager with
Spring's JTA transaction implementation. Both transaction demarcation
and data access code will work without changes, because they just use
the generic transaction management APIs.</para>
<para>For distributed transactions across multiple Hibernate session
factories, simply combine <classname>JtaTransactionManager</classname>
as a transaction strategy with multiple
<classname>LocalSessionFactoryBean</classname> definitions. Each DAO
then gets one specific <interfacename>SessionFactory</interfacename>
reference passed into its corresponding bean property. If all underlying
JDBC data sources are transactional container ones, a business service
can demarcate transactions across any number of DAOs and any number of
session factories without special regard, as long as it is using
<classname>JtaTransactionManager</classname> as the strategy.</para>
<programlisting language="xml"><beans>
<jee:jndi-lookup id="dataSource1" jndi-name="java:comp/env/jdbc/myds1"/>
<jee:jndi-lookup id="dataSource2" jndi-name="java:comp/env/jdbc/myds2"/>
<bean id="mySessionFactory1"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource1"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
</value>
</property>
</bean>
<bean id="mySessionFactory2"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource2"/>
<property name="mappingResources">
<list>
<value>inventory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.OracleDialect
</value>
</property>
</bean>
<bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory1"/>
</bean>
<bean id="myInventoryDao" class="product.InventoryDaoImpl">
<property name="sessionFactory" ref="mySessionFactory2"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
<property name="inventoryDao" ref="myInventoryDao"/>
</bean>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans></programlisting>
<para>Both <classname>HibernateTransactionManager</classname> and
<classname>JtaTransactionManager</classname> allow for proper JVM-level
cache handling with Hibernate, without container-specific transaction
manager lookup or a JCA connector (if you are not using EJB to initiate
transactions).<!--Is it clear that the parenthetical phrase applies to only *JCA connector* or does it apply to *without transaction manager lookup* also?
TR: OK. Reads OK to me, it applies to both. --></para>
<para><classname>HibernateTransactionManager</classname> can export the
Hibernate JDBC <interfacename>Connection</interfacename> to plain JDBC
access code, for a specific <interfacename>DataSource</interfacename>.
This capability allows for high-level transaction demarcation with mixed
Hibernate and JDBC data access completely without JTA, if you are
accessing only one database.
<classname>HibernateTransactionManager</classname> automatically exposes
the Hibernate transaction as a JDBC transaction if you have set up the
passed-in <interfacename>SessionFactory</interfacename> with a
<interfacename>DataSource</interfacename> through the
<classname>dataSource</classname> property of the
<classname>LocalSessionFactoryBean</classname> class. Alternatively, you
can specify explicitly the <interfacename>DataSource</interfacename> for
which the transactions are supposed to be exposed through the
<classname>dataSource</classname> property of the
<classname>HibernateTransactionManager</classname> class.</para>
</section>
<section id="orm-hibernate-resources">
<title>Comparing container-managed and locally defined resources<!--I've revised to better communicate the point of the section, which I think has to do with --><!--comparing spring's local support for transactions as opposed to container support. Revise as necessary.
TR: REVISED, PLS REVIEW. Changed to heading *resources* since it technically could be more than transactions i.e. caching--></title>
<para>You can switch between a container-managed JNDI
<interfacename>SessionFactory</interfacename><!--Clarify whether JNDI SessionFactory refers to container resources; I'm not sure what's being compared.
TR: REVISED, PLS REVIEW. Clarified by addin container-managed.--> and a
locally defined one, without having to change a single line of
application code. Whether to keep resource definitions in the container
or locally within the application is mainly a matter of the transaction
strategy that you use. Compared to a Spring-defined local
<interfacename>SessionFactory</interfacename>, a manually registered
JNDI <interfacename>SessionFactory</interfacename> does not provide any
benefits. Deploying a <interfacename>SessionFactory</interfacename>
through Hibernate's JCA connector provides the added value of
participating in the Java EE server's management infrastructure, but
does not add actual value beyond that.</para>
<para>Spring's transaction support is not bound to a container.
Configured with any strategy other than JTA, transaction support also
works in a stand-alone or test environment. Especially in the typical
case of single-database transactions, Spring's single-resource local
transaction support <!--I wrote *stand-alone transaction support*; if not correct, specify what you mean by *this*.
TR: REVISED, PLS REVIEW. Changed to single-resource local transaction support.-->is
a lightweight and powerful alternative to JTA. When you use local EJB
stateless session beans to drive transactions, you depend both on an EJB
container and JTA, even if you access only a single database, and only
use stateless session beans to provide declarative transactions through
container-managed transactions. <!--Does the next sentence refer to Spring or non-Spring? Clarify. I'm not sure whether the point of this paragraph and preceding is clear.
TR: REVISED, PLS REVIEW. It's not very clear. I've revised it. It refers to non-Spring programmatic use of JTA.-->Also,
direct use of JTA programmatically requires a Java EE environment as
well. JTA does not involve only container dependencies in terms of JTA
itself and of JNDI <interfacename>DataSource</interfacename> instances.
For non-Spring, JTA-driven Hibernate transactions, you have to use the
Hibernate JCA connector, or extra Hibernate transaction code with the
<interfacename>TransactionManagerLookup</interfacename> configured for
proper JVM-level caching.</para>
<para>Spring-driven transactions can work as well with a locally defined
Hibernate <interfacename>SessionFactory</interfacename> as they do with
a local JDBC <interfacename>DataSource </interfacename>if they are
accessing a single database. Thus you only have to use Spring's JTA
transaction strategy when you have distributed transaction requirements.
A JCA connector requires container-specific deployment steps, and
obviously JCA support in the first place. This configuration requires
more work than deploying a simple web application with local resource
definitions and Spring-driven transactions. Also, you often need the
Enterprise Edition of your container if you are using, for example,
WebLogic Express, which does not provide JCA. A Spring application with
local resources and transactions spanning one single database works in
any Java EE web container (without JTA, JCA, or EJB) such as Tomcat,
Resin, or even plain Jetty. Additionally, you can easily reuse such a
middle tier in desktop applications or test suites.</para>
<para>All things considered, if you do not use EJBs, stick with local
<interfacename>SessionFactory</interfacename> setup and Spring's
<classname>HibernateTransactionManager</classname> or
<classname>JtaTransactionManager</classname>. You get all of the
benefits, including proper transactional JVM-level caching and
distributed transactions, without the inconvenience of container
deployment. JNDI registration of a Hibernate
<interfacename>SessionFactory</interfacename> through the JCA connector
only adds value when used in conjunction with EJBs.</para>
</section>
<section id="orm-hibernate-invalid-jdbc-access-error">
<title>Spurious application server warnings with Hibernate</title>
<para>In some JTA environments with very strict
<interfacename>XADataSource</interfacename> implementations -- currently
only some WebLogic Server and WebSphere versions -- when Hibernate is
configured without regard to the JTA
<interfacename>PlatformTransactionManager</interfacename> object for
that environment, it is possible for spurious warning or exceptions to
show up in the application server log. These warnings or exceptions
indicate that the connection being accessed is no longer valid, or JDBC
access is no longer valid, possibly because the transaction is no longer
active. As an example, here is an actual exception from WebLogic:</para>
<programlisting>java.sql.SQLException: The transaction is no longer active - status: 'Committed'.
No further JDBC access is allowed within this transaction.</programlisting>
<para>You resolve this warning by simply making Hibernate aware of the
JTA <interfacename>PlatformTransactionManager</interfacename> instance,
to which it will synchronize (along with Spring). You have two options
for doing this:</para>
<itemizedlist>
<listitem>
<para>If in your application context you are already directly
obtaining the JTA
<interfacename>PlatformTransactionManager</interfacename> object
(presumably from JNDI through
<literal>JndiObjectFactoryBean/<literal><jee:jndi-lookup></literal></literal>)
and feeding it, for example, to Spring's
<classname>JtaTransactionManager</classname>, then the easiest way
is to specify a reference to the bean defining this JTA
<interfacename>PlatformTransactionManager</interfacename>
instance<!--Replace *this* with exactly what *this* refes to--> as
the value of the <property>jtaTransactionManager</property> property
for <classname>LocalSessionFactoryBean.</classname> Spring then makes
the object available to Hibernate.</para>
</listitem>
<listitem>
<para>More likely you do not already have the JTA
<interfacename>PlatformTransactionManager</interfacename> instance,
because Spring's <classname>JtaTransactionManager</classname> can
find it itself. <!--Re preceding sentence, if this is the case, then why would you need to do what first bullet describes?
TR: OK AS IS. This is very container dependent, and either case is possible.-->Thus
you need to configure Hibernate to look up JTA
<interfacename>PlatformTransactionManager</interfacename> directly.
You do this by configuring an application server- specific
<literal>TransactionManagerLookup</literal> class in the Hibernate
configuration, as described in the Hibernate manual.</para>
</listitem>
</itemizedlist>
<para>The remainder of this section describes the sequence of events
that occur with and without Hibernate's awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>.</para>
<para>When Hibernate is not configured with any awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>, the following
events occur when a JTA transaction commits:</para>
<orderedlist>
<listitem>
<para>The JTA transaction commits.</para>
</listitem>
<listitem>
<para>Spring's <classname>JtaTransactionManager</classname> is
synchronized to the JTA transaction, so it is called back through an
<emphasis>afterCompletion</emphasis> callback by the JTA transaction
manager.</para>
</listitem>
<listitem>
<para>Among other activities, this synchronization<!--Identify *this*. TR: REVISED, PLS REVIEW. Added "synchronization"--> can
trigger a callback by Spring to Hibernate, through Hibernate's
<literal>afterTransactionCompletion</literal> callback <!--Preceding line, is *afterTransactionCompletion* callback the same as *afterCompletion* callback in step 2? If so, revise so --><!--there is no redundancy, or at least refer to the two callbacks in the same way.
TR: OK AS IS. Two different callback methhods - one is Spring's (*afterCompletion*) and the other is Hibernate's (*afterTransactionCompletion*)-->(used
to clear the Hibernate cache), followed by an explicit
<literal>close()</literal> call on the Hibernate Session, which
causes Hibernate to attempt to <literal>close()</literal> the JDBC
Connection.</para>
</listitem>
<listitem>
<para>In some environments, this
<methodname>Connection.close()</methodname> call then triggers the
warning or error, as the application server no longer considers the
<interfacename>Connection</interfacename> usable at all, because the
transaction has already been committed.</para>
</listitem>
</orderedlist>
<para>When Hibernate is configured with awareness of the JTA
<interfacename>PlatformTransactionManager</interfacename>, the following
events occur when a JTA transaction commits:</para>
<orderedlist>
<listitem>
<para>the JTA transaction is ready to commit.</para>
</listitem>
<listitem>
<para>Spring's <classname>JtaTransactionManager</classname> is
synchronized to the JTA transaction, so the transaction is called
back through a <emphasis>beforeCompletion</emphasis> callback by the
JTA transaction manager.</para>
</listitem>
<listitem>
<para>Spring is aware that Hibernate itself is synchronized to the
JTA transaction, and behaves differently than in the previous
scenario. Assuming the Hibernate
<interfacename>Session</interfacename> needs to be closed at all,
Spring will close it now.</para>
</listitem>
<listitem>
<para>The JTA transaction commits.</para>
</listitem>
<listitem>
<para>Hibernate is synchronized to the JTA transaction, so the
transaction is called back through an
<emphasis>afterCompletion</emphasis> callback by the JTA transaction
manager, and can properly clear its cache.</para>
</listitem>
</orderedlist>
</section>
</section>
<section id="orm-jdo">
<title>JDO</title>
<para>Spring supports the standard JDO 2.0 and 2.1 APIs as data access
strategy, following the same style as the Hibernate support. The
corresponding integration classes reside in the
<literal>org.springframework.orm.jdo</literal> package.</para>
<section id="orm-jdo-setup">
<title><interfacename>PersistenceManagerFactory</interfacename>
setup</title>
<para>Spring provides a
<classname>LocalPersistenceManagerFactoryBean</classname> class that
allows you to define a local JDO
<interfacename>PersistenceManagerFactory</interfacename> within a Spring
application context:</para>
<programlisting language="xml"><beans>
<bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="configLocation" value="classpath:kodo.properties"/>
</bean>
</beans></programlisting>
<para>Alternatively, you can set up a
<interfacename>PersistenceManagerFactory</interfacename> through direct
instantiation of a
<interfacename>PersistenceManagerFactory</interfacename> implementation
class. A JDO <interfacename>PersistenceManagerFactory</interfacename>
implementation class follows the JavaBeans pattern, just like a JDBC
<interfacename>DataSource</interfacename> implementation class, which is
a natural fit for a configuration that uses Spring. This setup style
usually supports a Spring-defined JDBC
<interfacename>DataSource</interfacename>, passed into the
<classname>connectionFactory</classname> property. For example, for the
open source JDO implementation DataNucleus (formerly JPOX) (<ulink
url="http://www.datanucleus.org/">http://www.datanucleus.org/</ulink>),
this is the XML configuration of the
<interfacename>PersistenceManagerFactory</interfacename>
implementation:<!--complete the intro sentence; what does this example show? What is its purpose? TR: REVISED, PLS REVIEW.--></para>
<programlisting language="xml"><beans>
<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>
<bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close">
<property name="connectionFactory" ref="dataSource"/>
<property name="nontransactionalRead" value="true"/>
</bean>
</beans></programlisting>
<para>You can also set up JDO
<interfacename>PersistenceManagerFactory</interfacename> in the JNDI
environment of a Java EE application server, usually through the JCA
connector provided by the particular JDO implementation. Spring's
standard <literal>JndiObjectFactoryBean /
<literal><jee:jndi-lookup></literal></literal> can be used to
retrieve and expose such a
<interfacename>PersistenceManagerFactory</interfacename>. However,
outside an EJB context, no real benefit exists in holding the
<interfacename>PersistenceManagerFactory</interfacename> in JNDI: only
choose such a setup for a good reason. See <xref
linkend="orm-hibernate-resources" /> for a discussion; the arguments
there apply to JDO as well.</para>
</section>
<section id="orm-jdo-daos-straight">
<title>Implementing DAOs based on the plain JDO API</title>
<para>DAOs can also be written directly against plain JDO API, without
any Spring dependencies, by using an injected
<interfacename>PersistenceManagerFactory</interfacename>. The following