1 | P a g e Monday, January 11, 2010
Theory and experimental evaluation of object-‐
relational mapping optimization techniques
How to ORM and how not to ORM
by
Jeroen Bach
Supervisors: Hans Dekkers & Jurgen Vinju Company supervisors: Ingrid van Zaanen & Co Kooijman
Publication status: Openbaar Version: 1.0
Contents
1 ABSTRACT ...4
2 INTRODUCTION...5
3 RELATED WORK ...6
3.1 PATTERNS AND TECHNIQUES...6
3.2 PERFORMANCE MEASUREMENTS...6
3.3 THE OBJECT-‐RELATIONAL IMPEDANCE MISMATCH...7
4 INTRODUCTION TO HIBERNATE...8
4.1 RELATION QUERYING CONFIGURATION PRINCIPLES...9
4.2 MAPPING CONFIGURATION...11
4.3 APPLYING THE TYPE OF MAPPING CONFIGURATION...12
4.4 APPLYING THE FETCHING STRATEGY...14
5 THEORY OF HIBERNATES QUERY BEHAVIOUR...15
5.1 A NOTATION FOR QUERY BEHAVIOUR...15
5.2 BASIC BEHAVIOUR...16
5.3 IMPORTANT FACTORS...19
5.3.1 Bidirectional relationship ...19
5.3.2 Lazy configuration...19
5.3.3 Join fetching ...20
5.3.4 Recursive relationship ...21
5.3.5 Concatenating relationships...21
6 RESEARCH METHOD ...22
6.1 MEASURING THE PERFORMANCE...22
6.1.1 Environment set up ...22
6.1.2 Test set up ...23
6.1.3 Measurement set up ...24
6.2 PREVENTING BAD PERFORMANCE ONE TO MANY RELATIONSHIP IN ORACLE...24
6.3 FACTORS INFLUENCING THE PERFORMANCE...25
6.3.1 Object graph...26
6.3.2 Mapping configuration ...26
6.3.3 Actions on object graph ...27
6.3.4 Storage...27
6.4 STABILISATION...27
7 PERFORMANCE MEASUREMENTS...28
7.1 HYPOTHESES AND RESULTS...29
7.1.1 Testing the type of queries ...29
7.1.2 Testing the amount of queries ...33
7.1.3 Testing all factors...34
7.2 THREATS TO VALIDITY...48
7.2.1 Internal...48
7.2.2 External ...49
8 CONCLUSION ...50
8.1 REJECTED HYPOTHESES...50
8.2 RECOMMENDATIONS. ...50
9 FUTURE WORK...52
10 ACKNOWLEDGEMENTS ...53
11 BIBLIOGRAPHY...54
APPENDIX A: EXAMPLE MAPPINGS USED IN THIS RESEARCH ...57
APPENDIX B: RELATION QUERYING BEHAVIOUR...58
ONE TO ONE (NON-‐RECURSIVE)...58
ONE TO ONE (RECURSIVE) ...63
ONE TO MANY (NON-‐RECURSIVE) ...64
ONE TO MANY (RECURSIVE)...68
MANY TO MANY (NON-‐RECURSIVE)...71
MANY TO MANY (RECURSIVE) ...71
1 Abstract
When an object oriented written application has to make use of a relational database an ORM tool can be used to synchronize the object model with the tables in the database. An advantage of such an ORM tool is the support for automatic querying of related objects. This option allows the programmer to query one object and dereference their relationships to other objects without querying each reference manually. The ORM tool will perform this relation querying automatically for the programmer.
A popular ORM tool for Java is Hibernate. In this research we focus only on Hibernate and in particular on the querying of related objects. Configuring the Hibernate configuration files can control this querying of related objects.
As the mapping of Hibernate (or any ORM tool) can be configured in many ways, poor performance can be a result of “wrong” configuration. Therefore we investigated the effect these configurations will have on the performance.
2 Introduction
Hibernate is one of the major ORM (Object Relation Mapping) tools written in and for Java. An ORM tool handles the persistence of objects in memory to a relational database. One of the main tasks of this is retrieving objects from the database. A key feature of this task is the automatic retrieving of referenced objects (of the queried object) as well, making it possible to dereference the references through an entire object graph without specifying the retrieval of each related object programmatically.
Hibernate supports a lot of different mapping configurations for customizing this behaviour, blurring the “best” performing choice in a specific situation. The mapping configurations describe the object to table mapping and relation querying behaviour. Especially, relatively new users (to the Hibernate library) can make unknowing choices that will drastically deteriorate the performance of the tool, maybe causing the abandoning of its usage in total.
Therefore, the goal of this research is to help the programmer find the best performing mapping configuration. To realize this goal we investigate the query behaviour of Hibernate for each type of mapping configuration. Interpreting this behaviour into best performing choices can still be a difficult task. We therefore benchmark certain configurations as well.
This research will be led by the following research question and sub-‐research questions.
Research question
What is the effect on the performance of Hibernate querying objects when using different mapping configurations?
Sub-‐research question 1
What are the mapping configurations possibilities?
Sub-‐research question 2
What is their effect on the behaviour?
Sub-‐research question 3
What is the effect of the behaviour on the performance?
The structure of the rest of this thesis is as follows. First we will discuss related work in chapter 3.
After that we will give more detailed information about Hibernate and the mapping configurations in chapter 4, answering sub-‐research question 1. Then we analyse the querying behaviour of the mapping configurations in chapter 5, answering sub-‐research question 2. In the research method in chapter 6 we describe how we will perform our performance measurements and will describe and discuss the results in chapter 7, answering sub-‐research question 3. Finally we draw our conclusions in chapter 8, and indicate future work in chapter 9.
3 Related work
In [1] van Zyl et al. performed research on the performance of Hibernate compared to several other persistence techniques (like plain JDBC and object databases). They demonstrated the bad performance of Hibernate compared to these other techniques. In later research [2] they reviewed their implementation of Hibernate with a member of the Hibernate team, after several comments on the implementation by the Hibernate community. In this research they concluded that the performance gains when implementing the recommendations made by this member. They did not, afterwards, draw any conclusions on the performance of the renewed Hibernate implementation compared to the other persistence techniques. These recommendations are based on experience and rules of thumb.
We tried to improve their research and other research performing benchmarks with Hibernate by researching the effects on the performance of certain configurations available in Hibernate. With this knowledge we also try to help a programmer or researcher to implement a good performing Hibernate configuration for a specific situation.
Further research on the remaining configurations and possibilities of Hibernate and expanding it to other tools can help create more honest benchmarks in total.
3.1 Patterns and techniques
There are a great variety of patterns and techniques to achieve a good performing ORM and Hibernate implements several of these. W. Keller described a complete pattern language on this subject in [3, 4, 5]. Several others also described best practices, patterns and techniques (often also implemented by Hibernate) in [6, 7, 8, 9]. Applying these patterns and techniques can be achieved by adjusting the mapping configuration of Hibernate.
As demonstrated in [2] and the remainder of this thesis, this configuration of Hibernate can have great influence on the performance. Due to the great variety of possibilities and the needed in depth database knowledge, this configuration remains a difficult and error-‐prone task that can easily deteriorate the overall performance. Due to this fact several have tried to automate this task, by analyzing the runtime behaviour [10, 11], static code analysis [12, 13] or by model driven generation [14], but none supplies a fully functional solution yet.
We decided to clarify the behaviour of Hibernate and its effect on the performance using these possible configurations for tackling this problem manually.
3.2 Performance measurements
Measuring the performance of these persistence tools can be done by specialized benchmarks like:
OO7 (java variant) [1], PolePosition and Torpedo [15]. The OO7 benchmark was originally intended to test OODBMS (Object Oriented Database Management Systems) [16]. In [1] this benchmark is translated to Java and used to compare the performance of Hibernate (and PostgreSQL) with db4o1, by van Zyl et al. indicated in the first part of this chapter. The same author(s) also wrote PolePosition, to further investigate the findings of this (translated) OO7 benchmark. In our research we used PolePosition as the basis for our benchmark.
1 db4o is an object database created by Versant corporation.
Also it should be noted that [17, 18] wrote an ORM benchmark (“BenchORM”) with tests based on two real-‐life scenarios (the JDBC wrapper and the objects of the object model of this research were used in our tests).
3.3 The object-‐relational impedance mismatch
Benchmarking persistence tools fit in a greater research, finding the optimal solution of solving/bridging the gap between the object oriented and relational paradigm. An ORM tool (like Hibernate) tries to fill this gap. This gap is also often referred to as the object-‐relational impedance mismatch [19].
As Robert Green stated in [20], the problem of “impedance mismatch” materializes itself strongly in two fundamental ways. One way is regarding the development burden presented by the mismatch and the other is regarding the slower performance and/or resource consumption imposed. As standardization of these mapping has occurred over the last couple of years, the development burden has been decreased and productivity has improved. Also the issues of performance and resource utilization have been relieved. By solving the “impedance mismatch” with ORM tools the developer is equipped to create a good performing solution easier.
The use of object databases can also be an alternative since they have proven to be a better solution for certain kinds of applications [20]. However, this is out of scope of this research.
4 Introduction to Hibernate
In this part we will give some general information about Hibernate and will discuss the automatic retrieving of referenced objects (relation querying) in more detail.
Hibernate is an ORM (Object-‐Relational Mapping) library written in and for JAVA. An ORM is a communication layer between the application and the database (making use of the database drivers to send SQL statements), mapping an Object Oriented data model to a relational data model and handling the synchronisation of the two. For an overview of Hibernates architecture see Figure 1.
As both relational and object oriented paradigms are used, the terminology will slightly overlap. We speak of references when there is a relationship between objects and of relations when there is a relationship between tables.
Figure 1: Context diagram of components and layers in the Hibernate Architecture (source [21]).
In this research we focus only on the part where objects are queried from the database and will describe the other actions (like updating, deleting and inserting) in future work. Querying an object is the basic action also needed to perform the other actions of an ORM.
The Querying of objects can be initiated in two ways, by using the methods of the Hibernate API (Application Programming Interface) or dereferencing a reference. When dereferencing a reference the programmer has used the pointer in an object (retrieved by a method of the API) to access properties of the related object. When the API is used, the programmer has thus called a method that retrieves an object (or collection of objects). Objects retrieved with the API can be seen as the starting objects from which the dereferencing can begin.
The use of the API and the way these references are configured can have a great impact on the performance. From this API we only use one method (the .get()), the remaining methods are discussed in chapter 9 Future work. After using the method Hibernate will retrieve all referenced objects automatically. The “when” and “how” of this action can be configured by setting the (so called) fetching strategies and table representation. The object containing the reference will be referred to as the owning object from now on.
Hibernate
Java Database Drivers
4.1 Relation querying configuration principles
Hibernate supports several configurations to determine the behaviour of querying related objects from the database: the fetching strategy and the table representation.
In the Hibernate reference documentation [22] a distinction is made between four fetching strategies and setting the laziness of it. When a reference to an object is set to lazy, Hibernate will wait with the retrieval of this object until it is first accessed. For each strategy we quote the definition given by the Hibernate reference documentation [22].
-‐ Select Fetching: A second SELECT is used to retrieve the associated entity or collection.
Unless you explicitly disable lazy fetching by specifying lazy="false", this second select will only be executed when you access the association.
-‐ Join Fetching: Hibernate retrieves the associated instance or collection in the same SELECT, using an OUTER JOIN.
-‐ Subselect Fetching: A second SELECT 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 lazy="false", this second select will only be executed when you access the association.
-‐ Batch Fetching: Hibernate retrieves a batch of entity instances or collections in a single SELECT by specifying a list of primary or foreign keys.
The SubSelect and Batch Fetching strategy are performance optimizations of the Select Fetching strategy. They can only be applied to one-‐to-‐many and many-‐to-‐many relationships and will have effect only when the owning object is in a collection. We scoped our research to only the Join and Select Fetching strategies.
The second influence on the behaviour is the table representation. There will be more queries or joins when the amount of tables the objects are divided over increases. Hibernate supports 13 table representations; we created an overview of the possibilities in Figure 2. This diagram contains at the leftmost column the object relationships (that we investigated) and a number next to it that indicates how this relationship can be mapped to tables indicated at the rightmost column. Also only primary and foreign keys are shown in this diagram, the other (value) columns are left out.
Figure 2: Mapping objects and relationships
A B
1 - 1
n - m
1 - m
B A
B A
B A
B A
B A
B A
Legend ...
PK FK
Primairy Key Foreign Key U Unique constraint P Primairy key
constraint Table reference Composition
Uni-directional (for all relationships) Object
B A
Object reference representation
A A
A
FK FK
junction table P U PK
table A
P PK
table B P 7 1-1 with junction table
FK FK
junction table P P PK
table A
P PK
table B P 12 n-m with junction table
FK FK
junction table P P + U PK
table A
P PK
table B P 11 1-m with junction table
PK table A
P 4 1-1 unique foreign key
PK FK
table B P U
PK FK
table B P 8 1-m foreign key
PK table A
P PK
table A P
2 1-1 foreign key is primairy key
FK table B
P
Table representation
PK FK
table P
1-m recursive with foreign key 9
PK FK
table P U
1-1 recursive with foreign key 5
PK table
P FK
FK junction table
P U 1-1 recursive with junction table 6
PK table
P FK
FK junction table
P P + U 1-m recursive with junction table 10
PK table
P FK
FK junction table
P P n-m recursive with junction table 13
1 1-1 one table
PK table AB
P
N Table representation
Association / aggregation (Bi-directional) X
Only the owning object can have the foreign key in its table, if this is not desirable the relation should be made
bi-directional.
PK table B
P 3 1-1 unique foreign key
PK FK
table A P U Hibernate mapping possibilities
A
A
A B A
1 2 4
5 6 8
9 10
11 12
13 14
1 2
5 6 8
9 10
11 12
13 14
2 4 5 6 8
9 10
11 12
13 14
5 6 8
9 10
11 12
13 14
1 2
3 4
7 8
9 10
11 12
13 14
1 2
3 4
7 8
9 10
11 12
13 14
1 2
3 4
5 6
7 9 10 12
13 14
1 2
3 4
5 6
7 9 10 12
13 14
1 2
3 4
5 6
7 9 10 12
13 14
1 2
3 4
5 6
7 8
11 12
13 14
1 2
3 4
5 6
7 8
11 12
13 14
1 2
3 4
5 6
7 8
9 10
11 13 14
1 2
3 4
5 6
7 8
9 10
11 13 14
1 2
3 4
5 6
7 8
9 10
11 14
1 2
3 4
5 6
7 8
9 10
11 14
3 7
3 4
7
1 3 7
1 2
3 4
7
5 6
5 6
8 11
8 11
8 11
9 10
9 10
12
12
12
12 13
13
4.2 Mapping configuration
In the next part we will describe how references to other objects can be configured in Hibernate.
The mapping configuration of Hibernate is done in XML files, for an example see Code fragment 1. A good practise is to have a XML file for each Java class. With the introduction of annotations in Java 5, Hibernate now also supports configuring the mappings with annotations. In our research we performed the mapping configuration in XML files.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.polepos.teams.hibernate.data">
<class name="Person" table="person">
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<property name="firstName" column="firstname" length="40" />
<property name="lastName" column="lastName" length="40" />
<property name="age" column="age"/>
<many-to-one name="adress"
column="adressId"
unique="true"
not-null="false"
lazy="proxy" fetch="select"
cascade="all"/>
</class>
</hibernate-mapping>
Code fragment 1: Hibernate XML mapping file
When configuring the mappings we distinguish between two definitions, one describing the type of relationship and one describing how this type is eventually configured in the mapping documents (type of mapping configuration). Namely, there are four types of relationships that can be configured by six types of mapping configurations.
The four types of relationships are: one to one, one to many, many to one and many to many. There are six Hibernate mapping configuration types and a range of attributes to configure them. The types of mapping configuration indicate either a reference to a single object or to a collection of objects.
Using these types in different combinations, for both objects, can create the four types of relationships.
Mapping configuration type for configuring a reference to a single object:
-‐ component -‐ many-‐to-‐one -‐ one-‐to-‐one -‐ join
Mapping configuration type for configuring a reference to a collection of objects:
-‐ one-‐to-‐many -‐ many-‐to-‐many
In the next part we first describe how to apply the type of mapping configurations and after that how to apply the fetching strategies.
4.3 Applying the type of mapping configuration
In Table 1 we demonstrate how to create the table representations supported by Hibernate by listing the type of mapping configurations and key attributes (we used the XML notations for clarity). Note that the recursive table representations are equal to their non-‐recursive variant, but with a reference to their own class (we leave them out of the table to create a compacter overview).
Each Java object knows only about its own relationships. Configuring one or both objects of the relationship will therefore have different effects. Besides making the relationship bidirectional or unidirectional, it is also possible that some table representations cannot be created when configuring only one object. The optional sign will indicate that the relation can be unidirectional.
Table Representation (TR) Configuration object A Configuration object B
<component>2 with the properties of B within the start and closing tag.
No xml-‐mapping document needed. For a bidirectional
relationship, add the
<parent> element tag within the
<component> tag of object A.
<one-‐to-‐one> <one-‐to-‐one constrained=”true”>
<many-‐to-‐one unique=”true”>
(optional)
<one-‐to-‐one>
<one-‐to-‐one> <many-‐to-‐one unique=”true”>
<join>
<key>
<many-‐to-‐one unique=”true”>
(optional)
<join>
<key unique=”true”>
<many-‐to-‐one>
<set>
<one-‐to-‐many>
(optional)
<many-‐to-‐one>
<set>
<many-‐to-‐many unique=”true”>
(optional)
<join>
<key>
<many-‐to-‐one>
<set>
<many-‐to-‐many>
(optional)
<set>
<many-‐to-‐many>
Table 1: Type of mapping configurations
2 The <component> element maps properties of a child object to columns of the table of a parent class.
1 1-1 one table
PK tableAB
P
PK table A
P
2 1-1 foreign key is primairy key
FK table B
P
PK table B
P 3 1-1 unique foreign key
PK FK
table A P U
PK table A
P
4 1-1 unique foreign key
PK FK
table B P U
FK FK
junction table P U PK
table A
P PK
table B P 7 1-1 with junction table
PK FK
table B P 8 1-m foreign key
PK table A
P
FK FK
junction table P P + U PK
table A
P PK
table B P 11 1-m with junction table
FK FK
junction table P P PK
table A
P PK
table B P 12 n-m with junction table
In “Appendix A: Example mappings used in this research” we listed the relationship configuration we used in our test setups.
For more detail explanation see the Hibernate reference documentation [22].
4.4 Applying the fetching strategy
Each type of mapping configuration can be set to a specific fetching strategy, by setting three attributes (the possible values of the attributes are described below this list):
-‐ the lazy attribute: specifying when the reference needs to be retrieved (default: true|proxy);
-‐ the fetch attribute: specifies the query used to retrieve the reference (default: select);
-‐ the batch-‐size attribute: specifying of how many objects (in a collection) the relationship needs to be retrieved (default: 0).
The fetching strategy attributes will have no effect on the join and component mapping configuration types, because the join type will always force a join and the component type will force the storage of two objects into one table (making it not possible to join or perform separate select queries).
Not each one of the remaining configuration types can contain all these attributes. In the next list we created an overview of the possibilities (taken from the hibernate reference documentation [22]).
-‐ one-‐to-‐one
o fetch="join|select"
o lazy="proxy|no-‐proxy|false"
-‐ many-‐to-‐one:
o fetch="join|select"
o lazy="proxy|no-‐proxy|false"
-‐ set:
o fetch="join|select|subselect"
o lazy="true|extra|false"
o batch-‐size=”N”
-‐ many-‐to-‐many:
o fetch="select|join"
o lazy="true|extra|false"
For more detail see the Hibernate reference documentation [22].
5 Theory of Hibernates query behaviour
As hibernate communicates by sending SQL statements, the logical first step is to examine and create an overview of the executed SQL statements. With this overview we will form our query behaviour theory. Analyzing this theory will indicate the different factors that change when different mappings are applied, but not their effect on the performance. Therefore we will form several hypotheses based on this theory and execute performance measurements to test them in chapter 7.
We created this theory by examining the SQL queries executed by Hibernate when performing the following tests. We created for each mapping possibility a test containing objects (that implement the mapping configuration and fetching strategies). Then we retrieve the owning object and dereference the reference(s), while registering the executed SQL using Hibernates logging feature.
The theory explained in this chapter is the need to know basis for creating the query behaviour for every type of object model.
First we describe our notation and the basic behaviour of each mapping and after that we will describe the influences of the following configurations on the basic behaviour:
-‐ a bidirectional relationship;
-‐ lazy configuration;
-‐ join fetching;
-‐ recursive relationships; and -‐ concatenating relationships
For a complete understanding we worked out the behaviour for all relationships (one-‐to-‐one, one-‐to-‐
many and many-‐to-‐many) in Appendix B: Relation querying behaviour. These examples also demonstrate the behaviour of recursive and bidirectional relationships.
5.1 A notation for query behaviour
We present the SQL in the form described below. As SQL visualized in form of text will not contribute to the clarity of the overview, we decided to use a more visual representation of the result sets instead. In that representation we show the actual results in form of a table, leaving out the more unimportant detailed information. Figure 3 explains our notation.
Figure 3: Notation hibernate querying behaviour
5.2 Basic behaviour
In the next examples there will be an object A with a reference to object(s) B. For both objects we describe what type of mapping configuration is applied to it. The ResultSets indicate what queries were executed when object A and related object B are retrieved. When predicting the behaviour of the reference from object B back to A, it is possible to concatenate these isolated building blocks together. In this case it should be noted that the rules described in the other subchapters of this chapter must be applied as well.
To make the mapping configuration type more visible, we enclosed them in <…>.
With the <component> configuration type all properties of object B are included in the select query of A. See Figure 4. In this table representation both objects are stored in one table.
Figure 4: Query <component>
With the <one-‐to-‐one> configuration type another query is executed to retrieve object B (by foreign key). See Figure 5 and Figure 6. Both objects are stored in separate tables and the foreign key is stored in the table of object B. When applying only the <one-‐to-‐one> configuration type the foreign
The results of one query
The table(s) included in the results The columns included
of each table
PKA columnsA PKB columnsB
Table A Table B
ResultSet2 PKB FKA
D D FKA PKB PKB columnsB
D D FKA PKB PKB columnsB
... ... ... ... ... ...
PKA columnsA Table A ResultSet1
Duplicated columns from table A, due to the join
The dots indicate that there are more rows present.
This amount is equal to amount of objects.
A join between two tables
Table A has a 1 to N relationship to table B, therefore table B returns multiple
related rows for one row in A Indicates the possibility to execute this query lazy.
Thus only executing it when the objects (in this query) are accessed.
FKA2 PKA1 columnsA1
Table A ResultSet3
Overhead caused by bidirectional relationships.
D Duplicated values
Continues N amount of times, this can be rows or queries.
(where N is the amount of objects in the relation)
JT
Overhead when using a bidirectional relationship, compared to a unidirectional relationship.
Join
Indicates the possibility to execute this query lazy.
Columns from a Junctiontable.
Indicates the extra overhead when the bidirectional relationship back to object A is set to join fetching.
Legend
...
1 1-1 one table
PK table
P
1
PKA columnsA columnsB Table AB
ResultSet1
key is set as primary key in object B by default. Adding the <many-‐to-‐one> configuration type to the mapping of object B will make the foreign key a separate column in the table.
Figure 5: Queries <one-‐to-‐one>
Figure 6: Queries <one-‐to-‐one> on A and <many-‐to-‐one> on B
With the <many-‐to-‐one> configuration type also another query is executed to retrieve object B (by primary key). See Figure 7. Both objects are stored in separate tables, but the foreign key is stored in the table of object A. This introduces the possibility to execute the query for object B lazy. Meaning that Hibernate can create a proxy object for B, because after the first query the ID of object B is known. This proxy object will retrieve object B as soon as one of its properties is accessed.
Figure 7: Queries <many-‐to-‐one>
With the <join> and <many-‐to-‐one> configuration type the foreign key is joined in the first query and for object B another query is executed (by primary key). See Figure 8. Both objects are stored in separate tables and the foreign keys are stored in a separate table as well. Each object will therefore always be retrieved by their primary key, instead of sometimes also by the foreign key. This situation makes it possible to always execute the second query lazy, while the previous configurations did not allow this.
Figure 8: Queries <join> and <many-‐to-‐one>
With the <set> and <one-‐to-‐many> configuration type another query will retrieve all B’s connected to A (by foreign key). See Figure 9. For this relationship Hibernate requires two mapping configuration types. The <set> indicates that the results belong to a collection were the <one-‐to-‐
many> will indicate the type of relationship.
PK table A
P
2 1-1 foreign key is primairy key
FK table B
P
2
PKA columnsA PKB columnsB
Table A Table B
ResultSet1 ResultSet2
PK table A
P
4 1-1 unique foreign key
PK FK
table B P
U PKA columnsA PKB columnsB FKA
Table A Table B
ResultSet1 ResultSet2
4
PK table B
P 3 1-1 unique foreign key
PK FK
table A P
U PKA columnsA FKB PKB columnsB
Table B Table A
3 ResultSet1 ResultSet2
FK FK
junction table P U PK
table A
P PK
table B P
7 1-1 with junction table 7
FKB
PKA columnsA PKB columnsB
Table A JT Table B
ResultSet1 ResultSet2
In this case it is possible to execute the second query lazy as well because the collection will function as proxy object (waiting with the execution of the query until the collection is accessed).
Figure 9: Queries <set> and <one-‐to-‐many>
With the <set> and <many-‐to-‐many> another query will be executed to retrieve the foreign keys from the junction table and then for each related object a query is executed to retrieve it (by primary key). See Figure 10. Not changing this basic behaviour can increase the amount of executed queries drastically when the related objects increases. Note: When a unique constraint is added to the
<many-‐to-‐many> tag, the relation will be a one to many relationship.
Figure 10: Queries <set> and <many-‐to-‐many> with unique constraint
With the <set> and <many-‐to-‐many> (without a unique constraint) the behaviour is similar to the previous one to many relationship. See Figure 11. Note: When no unique constraint is added, the relation will be a many to many relationship.
Figure 11: Queries <set> and <many-‐to-‐many>
8
PKA columnsA PKB columnsB
Table A Table B
ResultSet1 ResultSet2
PKB FKA
PKB columnsB PKB
FKA
PKB columnsB PKB
FKA
... ...
...
...
PK FK
table B P 8 1-m foreign key
PK table A
P Select
11
PKA columnsA
Table A ResultSet1
FKA FKB
ResultSet2 JT
PKB columnsB
Table B ResultSet3
FKA FKB
FKA FKB
... ...
Select Select
PKB columnsB
Table B ResultSet4
... ...
...
...
FK FK
junction table P P + U PK
table A
P PK
table B P 11 1-m with junction table
12
PKA columnsA
Table A ResultSet1
FKA FKB
ResultSet2 JT
PKB columnsB
Table B ResultSet3
FKA FKB
FKA FKB
... ...
PKB columnsB
Table B ResultSet4
... ...
...
...
FK FK
junction table P P PK
table A
P PK
table B P 12 n-m with junction table
5.3 Important factors
To understand the query behaviour of a certain object model there are some important factors that change the basic behaviour described in chapter 5.2. In the next part we describe these factors.
5.3.1 Bidirectional relationship
In a bidirectional relationship both objects have configured a reference to each other by using the normal configuration types. When processing these configuration types, Hibernate will act as the default behaviour described (in the previous chapter). What should be mentioned is that the default behaviour is always preceded by a session cache lookup that can reduce the amount of queries when the object is retrieved before. Theoretically this should mean that when the reference back is processed no extra queries will be executed, but due to the working of the session cache this is not always the case. When performing a cache lookup, the ID (primary key) of the object has to be known. In chapter 5.2 we indicated that an object was queried by primary or by foreign key, in the case the object is queried by the primary key Hibernate can retrieve the object from the session cache. If this is not the case Hibernate will perform an extra query (retrieving the first object again).
In the following part we will demonstrate this behaviour by giving an example. Here we will retrieve object A, dereference the reference to object B and dereference it back to object A. With the table representation of Figure 12 an extra query for the reference from object B back to object A will be executed (because the table of object B does not contain the ID of object A). In Figure 13 object A can be retrieved from the session cache.
Figure 12: Object B cannot find object A in the cache
Figure 13: Object B can find object A in the cache
5.3.2 Lazy configuration
In 5.2 Basic behaviour we indicate with a if the query of a referenced object can be executed lazy. This sign represents two objects and dereferencing the reference of the left object to the right object. In lazily configured references this dereferencing is the trigger for the query of the right object to be executed.
When configuring the laziness of a reference, Hibernate distinguishes between a reference to a single object or to a collection of objects. When processing a lazy reference to a single object, a proxy object is created (to handle the lazy behaviour). When processing a lazy reference to a collection of objects, no proxy object is needed (due to the collection object that will handle the lazy behaviour).
In case of a reference to a collection of objects the query can always be executed lazy but when relating to single objects this is not always the case. To create a proxy object, the ID (primary key) of the proxied object is needed. In 5.2 Basic behaviour we indicated for each table representation
PK table B
P 3 1-1 unique foreign key
PK FK
table A P
U PKA columnsA FKB PKB columnsB
Table B Table A
3 ResultSet1 ResultSet2
Select
FKB
PKA columnsA
Table A ResultSet3
PK table A
P 4 1-1 unique foreign key
PK FK
table B P U
FKA
PKB columnsB
PKA columnsA
Table A Table B
ResultSet1 ResultSet2
4 Select