/
performance.xml
1693 lines (1345 loc) · 68.7 KB
/
performance.xml
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"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
]>
<chapter id="performance">
<title>Improving performance</title>
<section id="performance-fetching" revision="2">
<title>Fetching strategies</title>
<para>Hibernate uses a <emphasis>fetching strategy</emphasis> to retrieve
associated objects if the application needs to navigate the association.
Fetch strategies can be declared in the O/R mapping metadata, or
over-ridden by a particular HQL or <literal>Criteria</literal>
query.</para>
<para>Hibernate3 defines the following fetching strategies:</para>
<itemizedlist>
<listitem>
<para><emphasis>Join fetching</emphasis>: Hibernate retrieves the
associated instance or collection in the same
<literal>SELECT</literal>, using an <literal>OUTER
JOIN</literal>.</para>
</listitem>
<listitem>
<para><emphasis>Select fetching</emphasis>: a second
<literal>SELECT</literal> is used to retrieve the associated entity or
collection. Unless you explicitly disable lazy fetching by specifying
<literal>lazy="false"</literal>, this second select will only be
executed when you access the association.</para>
</listitem>
<listitem>
<para><emphasis>Subselect fetching</emphasis>: a second
<literal>SELECT</literal> is used to retrieve the associated
collections for all entities retrieved in a previous query or fetch.
Unless you explicitly disable lazy fetching by specifying
<literal>lazy="false"</literal>, this second select will only be
executed when you access the association.</para>
</listitem>
<listitem>
<para><emphasis>Batch fetching</emphasis>: an optimization strategy
for select fetching. Hibernate retrieves a batch of entity instances
or collections in a single <literal>SELECT</literal> by specifying a
list of primary or foreign keys.</para>
</listitem>
</itemizedlist>
<para>Hibernate also distinguishes between:</para>
<itemizedlist>
<listitem>
<para><emphasis>Immediate fetching</emphasis>: an association,
collection or attribute is fetched immediately when the owner is
loaded.</para>
</listitem>
<listitem>
<para><emphasis>Lazy collection fetching</emphasis>: a collection is
fetched when the application invokes an operation upon that
collection. This is the default for collections.</para>
</listitem>
<listitem>
<para><emphasis>"Extra-lazy" collection fetching</emphasis>:
individual elements of the collection are accessed from the database
as needed. Hibernate tries not to fetch the whole collection into
memory unless absolutely needed. It is suitable for large
collections.</para>
</listitem>
<listitem>
<para><emphasis>Proxy fetching</emphasis>: a single-valued association
is fetched when a method other than the identifier getter is invoked
upon the associated object.</para>
</listitem>
<listitem>
<para><emphasis>"No-proxy" fetching</emphasis>: a single-valued
association is fetched when the instance variable is accessed.
Compared to proxy fetching, this approach is less lazy; the
association is fetched even when only the identifier is accessed. It
is also more transparent, since no proxy is visible to the
application. This approach requires buildtime bytecode instrumentation
and is rarely necessary.</para>
</listitem>
<listitem>
<para><emphasis>Lazy attribute fetching</emphasis>: an attribute or
single valued association is fetched when the instance variable is
accessed. This approach requires buildtime bytecode instrumentation
and is rarely necessary.</para>
</listitem>
</itemizedlist>
<para>We have two orthogonal notions here: <emphasis>when</emphasis> is
the association fetched and <emphasis>how</emphasis> is it fetched. It is
important that you do not confuse them. We use <literal>fetch</literal> to
tune performance. We can use <literal>lazy</literal> to define a contract
for what data is always available in any detached instance of a particular
class.</para>
<section id="performance-fetching-lazy">
<title>Working with lazy associations</title>
<para>By default, Hibernate3 uses lazy select fetching for collections
and lazy proxy fetching for single-valued associations. These defaults
make sense for most associations in the majority of applications.</para>
<para>If you set <literal>hibernate.default_batch_fetch_size</literal>,
Hibernate will use the batch fetch optimization for lazy fetching. This
optimization can also be enabled at a more granular level.</para>
<para>Please be aware that access to a lazy association outside of the
context of an open Hibernate session will result in an exception. For
example:</para>
<programlisting role="JAVA">s = sessions.openSession();
Transaction tx = s.beginTransaction();
User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();
tx.commit();
s.close();
Integer accessLevel = (Integer) permissions.get("accounts"); // Error!</programlisting>
<para>Since the permissions collection was not initialized when the
<literal>Session</literal> was closed, the collection will not be able
to load its state. <emphasis>Hibernate does not support lazy
initialization for detached objects</emphasis>. This can be fixed by
moving the code that reads from the collection to just before the
transaction is committed.</para>
<para>Alternatively, you can use a non-lazy collection or association,
by specifying <literal>lazy="false"</literal> for the association
mapping. However, it is intended that lazy initialization be used for
almost all collections and associations. If you define too many non-lazy
associations in your object model, Hibernate will fetch the entire
database into memory in every transaction.</para>
<para>On the other hand, you can use join fetching, which is non-lazy by
nature, instead of select fetching in a particular transaction. We will
now explain how to customize the fetching strategy. In Hibernate3, the
mechanisms for choosing a fetch strategy are identical for single-valued
associations and collections.</para>
</section>
<section id="performance-fetching-custom" revision="4">
<title>Tuning fetch strategies</title>
<para>Select fetching (the default) is extremely vulnerable to N+1
selects problems, so we might want to enable join fetching in the
mapping document:</para>
<programlisting role="XML"><set name="permissions"
fetch="join">
<key column="userId"/>
<one-to-many class="Permission"/>
</set</programlisting>
<programlisting role="XML"><many-to-one name="mother" class="Cat" fetch="join"/></programlisting>
<para>The <literal>fetch</literal> strategy defined in the mapping
document affects:</para>
<itemizedlist>
<listitem>
<para>retrieval via <literal>get()</literal> or
<literal>load()</literal></para>
</listitem>
<listitem>
<para>retrieval that happens implicitly when an association is
navigated</para>
</listitem>
<listitem>
<para><literal>Criteria</literal> queries</para>
</listitem>
<listitem>
<para>HQL queries if <literal>subselect</literal> fetching is
used</para>
</listitem>
</itemizedlist>
<para>Irrespective of the fetching strategy you use, the defined
non-lazy graph is guaranteed to be loaded into memory. This might,
however, result in several immediate selects being used to execute a
particular HQL query.</para>
<para>Usually, the mapping document is not used to customize fetching.
Instead, we keep the default behavior, and override it for a particular
transaction, using <literal>left join fetch</literal> in HQL. This tells
Hibernate to fetch the association eagerly in the first select, using an
outer join. In the <literal>Criteria</literal> query API, you would use
<literal>setFetchMode(FetchMode.JOIN)</literal>.</para>
<para>If you want to change the fetching strategy used by
<literal>get()</literal> or <literal>load()</literal>, you can use a
<literal>Criteria</literal> query. For example:</para>
<programlisting role="JAVA">User user = (User) session.createCriteria(User.class)
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();</programlisting>
<para>This is Hibernate's equivalent of what some ORM solutions call a
"fetch plan".</para>
<para>A completely different approach to problems with N+1 selects is to
use the second-level cache.</para>
</section>
<section id="performance-fetching-proxies" revision="2">
<title>Single-ended association proxies</title>
<para>Lazy fetching for collections is implemented using Hibernate's own
implementation of persistent collections. However, a different mechanism
is needed for lazy behavior in single-ended associations. The target
entity of the association must be proxied. Hibernate implements lazy
initializing proxies for persistent objects using runtime bytecode
enhancement which is accessed via the CGLIB library.</para>
<para>At startup, Hibernate3 generates proxies by default for all
persistent classes and uses them to enable lazy fetching of
<literal>many-to-one</literal> and <literal>one-to-one</literal>
associations.</para>
<para>The mapping file may declare an interface to use as the proxy
interface for that class, with the <literal>proxy</literal> attribute.
By default, Hibernate uses a subclass of the class. <emphasis>The
proxied class must implement a default constructor with at least package
visibility. This constructor is recommended for all persistent
classes</emphasis>.</para>
<para>There are potential problems to note when extending this approach
to polymorphic classes.For example:</para>
<programlisting role="XML"><class name="Cat" proxy="Cat">
......
<subclass name="DomesticCat">
.....
</subclass>
</class></programlisting>
<para>Firstly, instances of <literal>Cat</literal> will never be
castable to <literal>DomesticCat</literal>, even if the underlying
instance is an instance of <literal>DomesticCat</literal>:</para>
<programlisting role="JAVA">Cat cat = (Cat) session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
DomesticCat dc = (DomesticCat) cat; // Error!
....
}</programlisting>
<para>Secondly, it is possible to break proxy
<literal>==</literal>:</para>
<programlisting role="JAVA">Cat cat = (Cat) session.load(Cat.class, id); // instantiate a Cat proxy
DomesticCat dc =
(DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat proxy!
System.out.println(cat==dc); // false</programlisting>
<para>However, the situation is not quite as bad as it looks. Even
though we now have two references to different proxy objects, the
underlying instance will still be the same object:</para>
<programlisting role="JAVA">cat.setWeight(11.0); // hit the db to initialize the proxy
System.out.println( dc.getWeight() ); // 11.0</programlisting>
<para>Third, you cannot use a CGLIB proxy for a <literal>final</literal>
class or a class with any <literal>final</literal> methods.</para>
<para>Finally, if your persistent object acquires any resources upon
instantiation (e.g. in initializers or default constructor), then those
resources will also be acquired by the proxy. The proxy class is an
actual subclass of the persistent class.</para>
<para>These problems are all due to fundamental limitations in Java's
single inheritance model. To avoid these problems your persistent
classes must each implement an interface that declares its business
methods. You should specify these interfaces in the mapping file where
<literal>CatImpl</literal> implements the interface
<literal>Cat</literal> and <literal>DomesticCatImpl</literal> implements
the interface <literal>DomesticCat</literal>. For example:</para>
<programlisting role="XML"><class name="CatImpl" proxy="Cat">
......
<subclass name="DomesticCatImpl" proxy="DomesticCat">
.....
</subclass>
</class></programlisting>
<para>Then proxies for instances of <literal>Cat</literal> and
<literal>DomesticCat</literal> can be returned by
<literal>load()</literal> or <literal>iterate()</literal>.</para>
<programlisting role="JAVA">Cat cat = (Cat) session.load(CatImpl.class, catid);
Iterator iter = session.createQuery("from CatImpl as cat where cat.name='fritz'").iterate();
Cat fritz = (Cat) iter.next();</programlisting>
<note>
<title>Note</title>
<para><literal>list()</literal> does not usually return
proxies.</para>
</note>
<para>Relationships are also lazily initialized. This means you must
declare any properties to be of type <literal>Cat</literal>, not
<literal>CatImpl</literal>.</para>
<para>Certain operations do <emphasis>not</emphasis> require proxy
initialization:</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>equals()</literal>: if the persistent class does not
override <literal>equals()</literal></para>
</listitem>
<listitem>
<para><literal>hashCode()</literal>: if the persistent class does
not override <literal>hashCode()</literal></para>
</listitem>
<listitem>
<para>The identifier getter method</para>
</listitem>
</itemizedlist>
<para>Hibernate will detect persistent classes that override
<literal>equals()</literal> or <literal>hashCode()</literal>.</para>
<para>By choosing <literal>lazy="no-proxy"</literal> instead of the
default <literal>lazy="proxy"</literal>, you can avoid problems
associated with typecasting. However, buildtime bytecode instrumentation
is required, and all operations will result in immediate proxy
initialization.</para>
</section>
<section id="performance-fetching-initialization" revision="1">
<title>Initializing collections and proxies</title>
<para>A <literal>LazyInitializationException</literal> will be thrown by
Hibernate if an uninitialized collection or proxy is accessed outside of
the scope of the <literal>Session</literal>, i.e., when the entity
owning the collection or having the reference to the proxy is in the
detached state.</para>
<para>Sometimes a proxy or collection needs to be initialized before
closing the <literal>Session</literal>. You can force initialization by
calling <literal>cat.getSex()</literal> or
<literal>cat.getKittens().size()</literal>, for example. However, this
can be confusing to readers of the code and it is not convenient for
generic code.</para>
<para>The static methods <literal>Hibernate.initialize()</literal> and
<literal>Hibernate.isInitialized()</literal>, provide the application
with a convenient way of working with lazily initialized collections or
proxies. <literal>Hibernate.initialize(cat)</literal> will force the
initialization of a proxy, <literal>cat</literal>, as long as its
<literal>Session</literal> is still open. <literal>Hibernate.initialize(
cat.getKittens() )</literal> has a similar effect for the collection of
kittens.</para>
<para>Another option is to keep the <literal>Session</literal> open
until all required collections and proxies have been loaded. In some
application architectures, particularly where the code that accesses
data using Hibernate, and the code that uses it are in different
application layers or different physical processes, it can be a problem
to ensure that the <literal>Session</literal> is open when a collection
is initialized. There are two basic ways to deal with this issue:</para>
<itemizedlist>
<listitem>
<para>In a web-based application, a servlet filter can be used to
close the <literal>Session</literal> only at the end of a user
request, once the rendering of the view is complete (the
<emphasis>Open Session in View</emphasis> pattern). Of course, this
places heavy demands on the correctness of the exception handling of
your application infrastructure. It is vitally important that the
<literal>Session</literal> is closed and the transaction ended
before returning to the user, even when an exception occurs during
rendering of the view. See the Hibernate Wiki for examples of this
"Open Session in View" pattern.</para>
</listitem>
<listitem>
<para>In an application with a separate business tier, the business
logic must "prepare" all collections that the web tier needs before
returning. This means that the business tier should load all the
data and return all the data already initialized to the
presentation/web tier that is required for a particular use case.
Usually, the application calls
<literal>Hibernate.initialize()</literal> for each collection that
will be needed in the web tier (this call must occur before the
session is closed) or retrieves the collection eagerly using a
Hibernate query with a <literal>FETCH</literal> clause or a
<literal>FetchMode.JOIN</literal> in <literal>Criteria</literal>.
This is usually easier if you adopt the <emphasis>Command</emphasis>
pattern instead of a <emphasis>Session Facade</emphasis>.</para>
</listitem>
<listitem>
<para>You can also attach a previously loaded object to a new
<literal>Session</literal> with <literal>merge()</literal> or
<literal>lock()</literal> before accessing uninitialized collections
or other proxies. Hibernate does not, and certainly
<emphasis>should</emphasis> not, do this automatically since it
would introduce impromptu transaction semantics.</para>
</listitem>
</itemizedlist>
<para>Sometimes you do not want to initialize a large collection, but
still need some information about it, like its size, for example, or a
subset of the data.</para>
<para>You can use a collection filter to get the size of a collection
without initializing it:</para>
<programlisting role="JAVA">( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()</programlisting>
<para>The <literal>createFilter()</literal> method is also used to
efficiently retrieve subsets of a collection without needing to
initialize the whole collection:</para>
<programlisting role="JAVA">s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();</programlisting>
</section>
<section id="performance-fetching-batch">
<title>Using batch fetching</title>
<para>Using batch fetching, Hibernate can load several uninitialized
proxies if one proxy is accessed. Batch fetching is an optimization of
the lazy select fetching strategy. There are two ways you can configure
batch fetching: on the class level and the collection level.</para>
<para>Batch fetching for classes/entities is easier to understand.
Consider the following example: at runtime you have 25
<literal>Cat</literal> instances loaded in a <literal>Session</literal>,
and each <literal>Cat</literal> has a reference to its
<literal>owner</literal>, a <literal>Person</literal>. The
<literal>Person</literal> class is mapped with a proxy,
<literal>lazy="true"</literal>. If you now iterate through all cats and
call <literal>getOwner()</literal> on each, Hibernate will, by default,
execute 25 <literal>SELECT</literal> statements to retrieve the proxied
owners. You can tune this behavior by specifying a
<literal>batch-size</literal> in the mapping of
<literal>Person</literal>:</para>
<programlisting role="XML"><class name="Person" batch-size="10">...</class></programlisting>
<para>Hibernate will now execute only three queries: the pattern is 10,
10, 5.</para>
<para>You can also enable batch fetching of collections. For example, if
each <literal>Person</literal> has a lazy collection of
<literal>Cat</literal>s, and 10 persons are currently loaded in the
<literal>Session</literal>, iterating through all persons will generate
10 <literal>SELECT</literal>s, one for every call to
<literal>getCats()</literal>. If you enable batch fetching for the
<literal>cats</literal> collection in the mapping of
<literal>Person</literal>, Hibernate can pre-fetch collections:</para>
<programlisting role="XML"><class name="Person">
<set name="cats" batch-size="3">
...
</set>
</class></programlisting>
<para>With a <literal>batch-size</literal> of 3, Hibernate will load 3,
3, 3, 1 collections in four <literal>SELECT</literal>s. Again, the value
of the attribute depends on the expected number of uninitialized
collections in a particular <literal>Session</literal>.</para>
<para>Batch fetching of collections is particularly useful if you have a
nested tree of items, i.e. the typical bill-of-materials pattern.
However, a <emphasis>nested set</emphasis> or a <emphasis>materialized
path</emphasis> might be a better option for read-mostly trees.</para>
</section>
<section id="performance-fetching-subselect">
<title>Using subselect fetching</title>
<para>If one lazy collection or single-valued proxy has to be fetched,
Hibernate will load all of them, re-running the original query in a
subselect. This works in the same way as batch-fetching but without the
piecemeal loading.</para>
<!-- TODO: Write more about this -->
</section>
<section id="performance-fetching-profiles">
<title>Fetch profiles</title>
<para>Another way to affect the fetching strategy for loading associated
objects is through something called a fetch profile, which is a named
configuration associated with the
<interfacename>org.hibernate.SessionFactory</interfacename> but enabled,
by name, on the <interfacename>org.hibernate.Session</interfacename>.
Once enabled on a <interfacename>org.hibernate.Session</interfacename>,
the fetch profile will be in affect for that
<interfacename>org.hibernate.Session</interfacename> until it is
explicitly disabled.</para>
<para>So what does that mean? Well lets explain that by way of an
example which show the different available approaches to configure a
fetch profile:</para>
<example>
<title>Specifying a fetch profile using
<classname>@FetchProfile</classname></title>
<programlisting role="XML">@Entity
@FetchProfile(name = "customer-with-orders", fetchOverrides = {
@FetchProfile.FetchOverride(entity = Customer.class, association = "orders", mode = FetchMode.JOIN)
})
public class Customer {
@Id
@GeneratedValue
private long id;
private String name;
private long customerNumber;
@OneToMany
private Set<Order> orders;
// standard getter/setter
...
}</programlisting>
</example>
<example>
<title>Specifying a fetch profile using
<literal><fetch-profile></literal> outside
<literal><class></literal> node</title>
<programlisting role="XML"><hibernate-mapping>
<class name="Customer">
...
<set name="orders" inverse="true">
<key column="cust_id"/>
<one-to-many class="Order"/>
</set>
</class>
<class name="Order">
...
</class>
<fetch-profile name="customer-with-orders">
<fetch entity="Customer" association="orders" style="join"/>
</fetch-profile>
</hibernate-mapping>
</programlisting>
</example>
<example>
<title>Specifying a fetch profile using
<literal><fetch-profile></literal> inside
<literal><class></literal> node</title>
<programlisting role="XML"><hibernate-mapping>
<class name="Customer">
...
<set name="orders" inverse="true">
<key column="cust_id"/>
<one-to-many class="Order"/>
</set>
<fetch-profile name="customer-with-orders">
<fetch association="orders" style="join"/>
</fetch-profile>
</class>
<class name="Order">
...
</class>
</hibernate-mapping>
</programlisting>
</example>
<para>Now normally when you get a reference to a particular customer,
that customer's set of orders will be lazy meaning we will not yet have
loaded those orders from the database. Normally this is a good thing.
Now lets say that you have a certain use case where it is more efficient
to load the customer and their orders together. One way certainly is to
use "dynamic fetching" strategies via an HQL or criteria queries. But
another option is to use a fetch profile to achieve that. The following
code will load both the customer <emphasis>and</emphasis>their
orders:</para>
<example>
<title>Activating a fetch profile for a given
<classname>Session</classname></title>
<programlisting role="JAVA">Session session = ...;
session.enableFetchProfile( "customer-with-orders" ); // name matches from mapping
Customer customer = (Customer) session.get( Customer.class, customerId );
</programlisting>
</example>
<note>
<para><classname>@FetchProfile </classname>definitions are global and
it does not matter on which class you place them. You can place the
<classname>@FetchProfile</classname> annotation either onto a class or
package (package-info.java). In order to define multiple fetch
profiles for the same class or package
<classname>@FetchProfiles</classname> can be used.</para>
</note>
<para>Currently only join style fetch profiles are supported, but they
plan is to support additional styles. See <ulink
url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3414">HHH-3414</ulink>
for details.</para>
</section>
<section id="performance-fetching-lazyproperties">
<title>Using lazy property fetching</title>
<para>Hibernate3 supports the lazy fetching of individual properties.
This optimization technique is also known as <emphasis>fetch
groups</emphasis>. Please note that this is mostly a marketing feature;
optimizing row reads is much more important than optimization of column
reads. However, only loading some properties of a class could be useful
in extreme cases. For example, when legacy tables have hundreds of
columns and the data model cannot be improved.</para>
<para>To enable lazy property loading, set the <literal>lazy</literal>
attribute on your particular property mappings:</para>
<programlisting role="XML"><class name="Document">
<id name="id">
<generator class="native"/>
</id>
<property name="name" not-null="true" length="50"/>
<property name="summary" not-null="true" length="200" lazy="true"/>
<property name="text" not-null="true" length="2000" lazy="true"/>
</class></programlisting>
<para>Lazy property loading requires buildtime bytecode instrumentation.
If your persistent classes are not enhanced, Hibernate will ignore lazy
property settings and return to immediate fetching.</para>
<para>For bytecode instrumentation, use the following Ant task:</para>
<programlisting role="XML"><target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
<classpath path="${jar.path}"/>
<classpath path="${classes.dir}"/>
<classpath refid="lib.class.path"/>
</taskdef>
<instrument verbose="true">
<fileset dir="${testclasses.dir}/org/hibernate/auction/model">
<include name="*.class"/>
</fileset>
</instrument>
</target></programlisting>
<para>A different way of avoiding unnecessary column reads, at least for
read-only transactions, is to use the projection features of HQL or
Criteria queries. This avoids the need for buildtime bytecode processing
and is certainly a preferred solution.</para>
<para>You can force the usual eager fetching of properties using
<literal>fetch all properties</literal> in HQL.</para>
</section>
</section>
<section id="performance-cache" revision="1">
<title>The Second Level Cache</title>
<para>A Hibernate <literal>Session</literal> is a transaction-level cache
of persistent data. It is possible to configure a cluster or JVM-level
(<literal>SessionFactory</literal>-level) cache on a class-by-class and
collection-by-collection basis. You can even plug in a clustered cache. Be
aware that caches are not aware of changes made to the persistent store by
another application. They can, however, be configured to regularly expire
cached data.</para>
<para revision="1">You have the option to tell Hibernate which caching
implementation to use by specifying the name of a class that implements
<literal>org.hibernate.cache.CacheProvider</literal> using the property
<literal>hibernate.cache.provider_class</literal>. Hibernate is bundled
with a number of built-in integrations with the open-source cache
providers that are listed in <xref linkend="cacheproviders" />. You can
also implement your own and plug it in as outlined above. Note that
versions prior to Hibernate 3.2 use EhCache as the default cache
provider.</para>
<table frame="topbot" id="cacheproviders" revision="1">
<title>Cache Providers</title>
<tgroup align="left" cols="5" colsep="1" rowsep="1">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="3*" />
<colspec colname="c3" colwidth="1*" />
<colspec colname="c4" colwidth="1*" />
<colspec colname="c5" colwidth="1*" />
<thead>
<row>
<entry>Cache</entry>
<entry>Provider class</entry>
<entry>Type</entry>
<entry>Cluster Safe</entry>
<entry>Query Cache Supported</entry>
</row>
</thead>
<tbody>
<row>
<entry>Hashtable (not intended for production use)</entry>
<entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
<entry>memory</entry>
<entry></entry>
<entry>yes</entry>
</row>
<row>
<entry>EHCache</entry>
<entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
<entry>memory, disk, transactional, clustered</entry>
<entry>yes</entry>
<entry>yes</entry>
</row>
<row>
<entry>OSCache</entry>
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
<entry>memory, disk</entry>
<entry></entry>
<entry>yes</entry>
</row>
<row>
<entry>SwarmCache</entry>
<entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
<entry>clustered (ip multicast)</entry>
<entry>yes (clustered invalidation)</entry>
<entry></entry>
</row>
<row>
<entry>JBoss Cache 1.x</entry>
<entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
<entry>clustered (ip multicast), transactional</entry>
<entry>yes (replication)</entry>
<entry>yes (clock sync req.)</entry>
</row>
<row>
<entry>JBoss Cache 2</entry>
<entry><literal>org.hibernate.cache.jbc.JBossCacheRegionFactory</literal></entry>
<entry>clustered (ip multicast), transactional</entry>
<entry>yes (replication or invalidation)</entry>
<entry>yes (clock sync req.)</entry>
</row>
</tbody>
</tgroup>
</table>
<section id="performance-cache-mapping" revision="2">
<title>Cache mappings</title>
<para>As we have done in previous chapters we are looking at the two
different possibiltites to configure caching. First configuration via
annotations and then via Hibernate mapping files.</para>
<para>By default, entities are not part of the second level cache and we
recommend you to stick to this setting. However, you can override this
by setting the <literal>shared-cache-mode</literal> element in your
<filename>persistence.xml</filename> file or by using the
<literal>javax.persistence.sharedCache.mode </literal>property in your
configuration. The following values are possible:</para>
<itemizedlist>
<listitem>
<para><literal>ENABLE_SELECTIVE</literal> (Default and recommended
value): entities are not cached unless explicitly marked as
cacheable.</para>
</listitem>
<listitem>
<para><literal>DISABLE_SELECTIVE</literal>: entities are cached
unless explicitly marked as not cacheable.</para>
</listitem>
<listitem>
<para><literal>ALL</literal>: all entities are always cached even if
marked as non cacheable.</para>
</listitem>
<listitem>
<para><literal>NONE</literal>: no entity are cached even if marked
as cacheable. This option can make sense to disable second-level
cache altogether.</para>
</listitem>
</itemizedlist>
<para>The cache concurrency strategy used by default can be set globaly
via the
<literal>hibernate.cache.default_cache_concurrency_strategy</literal>
configuration property. The values for this property are:</para>
<itemizedlist>
<listitem>
<para><literal>read-only</literal></para>
</listitem>
<listitem>
<para><literal>read-write</literal></para>
</listitem>
<listitem>
<para><literal>nonstrict-read-write</literal></para>
</listitem>
<listitem>
<para><literal>transactional</literal></para>
</listitem>
</itemizedlist>
<note>
<para>It is recommended to define the cache concurrency strategy per
entity rather than using a global one. Use the
<classname>@org.hibernate.annotations.Cache</classname> annotation for
that.</para>
</note>
<example id="example-cache-concurrency-with-cache-annotation">
<title>Definition of cache concurrency strategy via
<classname>@Cache</classname></title>
<programlisting language="JAVA" role="JAVA">@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }</programlisting>
</example>
<para>Hibernate also let's you cache the content of a collection or the
identifiers if the collection contains other entities. Use the
<classname>@Cache</classname> annotation on the collection
property.</para>
<example>
<title>Caching collections using annotations</title>
<programlisting language="JAVA" role="JAVA">@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
return tickets;
}</programlisting>
</example>
<para><xref linkend="example-cache-annotation-with-attributes" />shows
the<literal> @org.hibernate.annotations.Cache</literal> annotations with
its attributes. It allows you to define the caching strategy and region
of a given second level cache.</para>
<example id="example-cache-annotation-with-attributes">
<title><classname>@Cache</classname> annotation with
attributes</title>
<programlistingco>
<areaspec>
<area coords="2" id="cache-hm1" />
<area coords="3" id="cache-hm2" />
<area coords="4" id="cache-hm3" />
</areaspec>
<programlisting>@Cache(
CacheConcurrencyStrategy usage();
String region() default "";
String include() default "all";
)</programlisting>
<calloutlist>
<callout arearefs="cache-hm1">
<para>usage: the given cache concurrency strategy (NONE,
READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE,
TRANSACTIONAL)</para>
</callout>
<callout arearefs="cache-hm2">
<para>region (optional): the cache region (default to the fqcn
of the class or the fq role name of the collection)</para>
</callout>
<callout arearefs="cache-hm3">
<para><literal>include</literal> (optional): all to include all
properties, non-lazy to only include non lazy properties
(default all).</para>
</callout>
</calloutlist>
</programlistingco>
</example>
<para>Let's now take a look at Hibernate mapping files. There the
<literal><cache></literal> element of a class or collection
mapping is used to configure the second level cache. Looking at <xref
linkend="example-hibernate-cache-mapping-element" /> the parallels to
anotations is obvious.</para>
<example id="example-hibernate-cache-mapping-element">
<title>The Hibernate <literal><cache></literal> mapping
element</title>
<programlistingco>
<areaspec>
<area coords="2" id="cache1" />
<area coords="3" id="cache2" />
<area coords="4" id="cache3" />
</areaspec>
<programlisting><cache
usage="transactional|read-write|nonstrict-read-write|read-only"
region="RegionName"
include="all|non-lazy"
/></programlisting>
<calloutlist>
<callout arearefs="cache1">
<para><literal>usage</literal> (required) specifies the caching
strategy: <literal>transactional</literal>,
<literal>read-write</literal>,
<literal>nonstrict-read-write</literal> or
<literal>read-only</literal></para>
</callout>
<callout arearefs="cache2">