Quick Refresh : Hibernate

What is ORM?
ORM stands for Object-Relational Mapping (ORM) is a programming technique for converting data between relational databases and object-oriented programming languages.

Why do you need ORM tools like hibernate?
The main advantage of ORM like hibernate is that it shields developers from messy SQL. Apart from this, ORM provides the following benefits:
  • Improved productivity
    • High-level object-oriented API
    • Less Java code to write
    • No SQL to write
  • Improved performance
    • Sophisticated caching
    • Lazy loading
    • Eager loading
  • Improved maintainability
    • A lot less code to write
  • Improved portability
    • ORM framework generates database-specific SQL for you
Hibernate is an Object-Relational Mapping(ORM) solution for JAVA. It is a powerful, high performance Object-Relational Persistence and Query service for any Java Application.Hibernate maps Java classes to database tables and from Java data types to SQL data types and relieve the developer from 95% of common data persistence related programming tasks.
Hibernate sits between traditional Java objects and database server to handle all the work in persisting those objects based on the appropriate O/R mechanisms and patterns.
Hibernate Advantages:
  • Hibernate takes care of mapping Java classes to database tables using XML files and without writing any line of code.
  • Provides simple APIs for storing and retrieving Java objects directly to and from the database.
  • If there is change in Database or in any table then the only need to change XML file properties.
  • Abstract away the unfamiliar SQL types and provide us to work around familiar Java Objects.
  • Hibernate does not require an application server to operate.
  • Manipulates Complex associations of objects of your database.
  • Minimize database access with smart fetching strategies.
  • Provides Simple querying of data.

Hibernate Architecture:The Hibernate architecture is layered to keep you isolated from having to know the underlying APIs. Hibernate makes use of the database and configuration data to provide persistence services (and persistent objects) to the application.
Following is a very high level view of the Hibernate Application Architecture. 
image.png
Hibernate uses various existing Java APIs, like JDBC, Java Transaction API(JTA), and Java Naming and Directory Interface (JNDI). JDBC provides a rudimentary level of abstraction of functionality common to relational databases, allowing almost any database with a JDBC driver to be supported by Hibernate. JNDI and JTA allow Hibernate to be integrated with J2EE application servers.
Following section gives brief description of each of the class objects involved in Hibernate Application Architecture.
Configuration Object: The Configuration object is the first Hibernate object you create in any Hibernate application and usually created only once during application initialization. It represents a configuration or properties file required by the Hibernate. The Configuration object provides two keys components:
  • Database Connection: This is handled through one or more configuration files supported by Hibernate. These files are hibernate.properties and hibernate.cfg.xml.
  • Class Mapping Setup
    This component creates the connection between the Java classes and database tables..
SessionFactory Object: Configuration object is used to create a SessionFactory object which in turn configures Hibernate for the application using the supplied configuration file and allows for a Session object to be instantiated. It acts as single data store and is a thread safe object and used by all the threads of an application. Also internal state of SessionFactory, which contains all meta data about Object/Relational mapping is Immutable and can not be changed once created.The SessionFactory is heavyweight object so usually it is created during application start up and kept for later use. You would need one SessionFactory object per database using a separate configuration file. So if you are using multiple databases then you would have to create multiple SessionFactory objects.
 SessionFactory sessionFactory = new Configuration( ).configure( ).buildSessionfactory( ); 
Session Object: Session object wraps a JDBC connection factory for Transaction, so it is used to get a physical connection with a database. It represents a single unit-of-work with the database. The Session object is lightweight and designed to be instantiated each time an interaction is needed with the database. Persistent objects are saved and retrieved through a Session object.  Session holds a mandatory (first-level) cache of persistent objects, used when navigating the object graph or looking up objects by identifier
The session objects should not be kept open for a long time because they are not usually thread safe, it means you can not share Hibernate Session between multiple threads.
To avoid creating too many sessions ThreadLocal class can be used as shown below to get the current session no matter how many times you make call to the currentSession( ) method. 
public class HibernateUtil {  
    public static final ThreadLocal local = new ThreadLocal(); 
    public static Session currentSession() throws HibernateException { 
         Session session = (Session) local.get(); 
         //open a new session if this thread has no session 
        if(session == null) { 
            session = sessionFactory.openSession(); 
            local.set(session); 
       } 
        return session; 
    } 
}  
Transaction Object: A Transaction represents a unit of work with the database and most of the RDBMS supports transaction functionality. Transactions in Hibernate are handled by an underlying transaction manager and transaction (from JDBC or JTA).
This is an optional object and Hibernate applications may choose not to use this interface, instead managing transactions in their own application code.
Query Object:  Query objects use SQL or Hibernate Query Language (HQL) string to retrieve data from the database and create objects. A Query instance is used to bind query parameters, limit the number of results returned by the query, and finally to execute the query.
Criteria Object: Criteria object are used to create and execute object oriented criteria queries to retrieve objects.
Second-level cache : It is used to store objects across sessions. This needs to be explicitly enabled and one would be required to provide the cache provider for a second-level cache. One of the common second-level cache providers is EhCache. 
Hibernate Configuration Hibernate requires to know in advance where to find the mapping information that defines how your Java classes relate to the database tables. Hibernate also requires a set of configuration settings related to database and other related parameters. All such information is usually supplied as a standard Java properties file called hibernate.properties, or as an XML file named hibernate.cfg.xml.
I will consider XML formatted file hibernate.cfg.xml to specify required Hibernate properties in my examples. Most of the properties take their default values and it is not required to specify them in the property file unless it is really required. This file is kept in the root directory of your application's classpath.
Hibernate Properties:
Following is the list of important properties you would require to configure for a databases in a standalone situation:

S.N.
Properties and Description
1hibernate.dialect  This property makes Hibernate generate the appropriate SQL for the chosen database.
2hibernate.connection.driver_class  The JDBC driver class.
3hibernate.connection.url The JDBC URL to the database instance.
4hibernate.connection.username The database username.
5hibernate.connection.password The database password.
6hibernate.connection.pool_size Limits the number of connections waiting in the Hibernate database connection pool.
7hibernate.connection.autocommit Allows autocommit mode to be used for the JDBC connection.

If you are using a database along with an application server and JNDI then you would have to configure the following properties:

S.N.
Properties and Description
1hibernate.connection.datasource The JNDI name defined in the application server context you?re using for the application.
2hibernate.jndi.class The InitialContext class for JNDI.
3hibernate.jndi.<JNDIpropertyname>  Passes any JNDI property you like to the JNDI InitialContext.
4hibernate.jndi.url Provides the URL for JNDI.
5hibernate.connection.username The database username.
6hibernate.connection.password The database password.
If you want to see the Hibernate generated SQL statements on console, what should we do?
In Hibernate configuration file set:  <property name="show_sql">true</property>
Hibernate with MySQL Database:MySQL is one of the most popular open-source database systems available today. Let us create hibernate.cfg.xml configuration file and place it in the root of your application's classpath. You would have to make sure that you have testdb database available in your MySQL database and you have a user test available to access the database.
The XML configuration file must conform to the Hibernate 3 Configuration DTD, which is available from http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"
http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

  <!-- Assume test is the database name -->
  <property name="hibernate.connection.url">jdbc:mysql://localhost/test</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.connection.password">root123</property>

  <!-- List of XML mapping files -->
  <mapping resource="Employee.hbm.xml"/>

</session-factory>
</hibernate-configuration>

The above configuration file includes <mapping> tags which are related to hibernate-mapping file and we will see in next chapter what exactly is a hibernate mapping file and how and why do we use it.

Hibernate Annotation: All the JPA annotations are defined in the javax.persistence package.  Hibernate Annotations are based on the JPA 2 specification and support all the features.
@Entity: @Entity annotation marks a class as an entity bean, so it must have a no-argument constructor that is visible with at least protected scope.

@Table : The @Table annotation allows you to specify the details of the table that will be used to persist the entity in the database.  If you don't use @Table annotation, hibernate will use the class name as the table name by default. The @Table annotation provides four attributes, allowing you to override the name of the table, its catalogue, and its schema, and enforce unique constraints on columns in the table. For now, we are using just table name, which is EMPLOYEE.

@Id and @GeneratedValue Annotations
Each entity bean will have a primary key, which you annotate on the class with the @Id annotation. The primary key can be a single field or a combination of multiple fields depending on your table structure.

By default, the @Id annotation will automatically determine the most appropriate primary key generation strategy to be used but you can override this by applying the @GeneratedValue annotation, which takes two parameters strategy and generator that I'm not going to discuss here, so let us use only the default key generation strategy. Letting Hibernate determine which generator type to use makes your code portable between different databases.

@Column Annotation :The @Column annotation is used to specify the details of the column to which a field or property will be mapped. You can use column annotation with the following most commonly used attributes −
  • name attribute permits the name of the column to be explicitly specified.
  • length attribute permits the size of the column used to map a value particularly for a String value.
  • nullable attribute permits the column to be marked NOT NULL when the schema is generated.
  • unique attribute permits the column to be marked as containing only unique values.
Hibernate Inheritance Mapping:
We can map the inheritance hierarchy classes with the table of the database. There are three inheritance mapping strategies defined in the hibernate:

(1)Table Per Hierarchy : In table per hierarchy mapping, single table is required to map the whole hierarchy, an extra column (known as discriminator column) is added to identify the class. But nullable values are stored in the table. You need to use @Inheritance(strategy=InheritanceType.SINGLE_TABLE), @DiscriminatorColumn and @DiscriminatorValue annotations for mapping table per hierarchy strategy.
image.png
  1. File: Employee.java
    1. package com.javatpoint.mypackage;  
    2. import javax.persistence.*;  
    3.   
    4. @Entity  
    5. @Table(name = "employee101")  
    6. @Inheritance(strategy=InheritanceType.SINGLE_TABLE)  
    7. @DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)  
    8. @DiscriminatorValue(value="employee")    
    9. public class Employee {  
    10. @Id  
    11. @GeneratedValue(strategy=GenerationType.AUTO)  
    12.       
    13. @Column(name = "id")  
    14. private int id;  
    15.   
    16. @Column(name = "name")  
    17. private String name;  
    18.   
    19. //setters and getters  
    20. }  
    File: Regular_Employee.java
    1. package com.javatpoint.mypackage;    
    2. import javax.persistence.*;    
    3. @Entity  
    4. @DiscriminatorValue("regularemployee")  
    5. public class Regular_Employee extends Employee{  
    6.       
    7. @Column(name="salary")    
    8. private float salary;  
    9.   
    10. @Column(name="bonus")     
    11. private int bonus;  
    12.   
    13. //setters and getters  
    14. }  
    File: Contract_Employee.java
    1. package com.javatpoint.mypackage;  
    2.   
    3. import javax.persistence.Column;  
    4. import javax.persistence.DiscriminatorValue;  
    5. import javax.persistence.Entity;  
    6.   
    7. @Entity  
    8. @DiscriminatorValue("contractemployee")  
    9. public class Contract_Employee extends Employee{  
    10.       
    11.     @Column(name="pay_per_hour")  
    12.     private float pay_per_hour;  
    13.       
    14.     @Column(name="contract_duration")  
    15.     private String contract_duration;  
    16.   
    17.     //setters and getters  
    18. }  
  2. The table structure for this hierarchy is as shown below:
    table per class hierarchy table  
(2) Table Per Concrete class :  In case of table per concrete class, tables are created as per class. But duplicate column is added in subclass tables. we need to use @Inheritance(strategy =InheritanceType.TABLE_PER_CLASS) annotation in the parent class and @AttributeOverrides annotation in the subclasses.

  1. @Entity  
  2. @Table(name = "employee102")  
  3. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)    
  4. public class Employee {  
  5. @Id  
  6. @GeneratedValue(strategy=GenerationType.AUTO)  
  7.       
  8. @Column(name = "id")  
  9. private int id;  
  10.   
  11. @Column(name = "name")  
  12. private String name;  
  13.   
  14. //setters and getters  
  15. }  
File: Regular_Employee.java
  1. package com.javatpoint.mypackage;  
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name="regularemployee102")  
  6. @AttributeOverrides({  
  7.     @AttributeOverride(name="id", column=@Column(name="id")),  
  8.     @AttributeOverride(name="name", column=@Column(name="name"))  
  9. })  
  10. public class Regular_Employee extends Employee{  
  11.       
  12. @Column(name="salary")    
  13. private float salary;  
  14.   
  15. @Column(name="bonus")     
  16. private int bonus;  
  17.   
  18. //setters and getters  
  19. }  
File: Contract_Employee.java
  1. package com.javatpoint.mypackage;  
  2. import javax.persistence.*;  

  3. @Entity  
  4. @Table(name="contractemployee102")  
  5. @AttributeOverrides({  
  6.     @AttributeOverride(name="id", column=@Column(name="id")),  
  7.     @AttributeOverride(name="name", column=@Column(name="name"))  
  8. })  
  9. public class Contract_Employee extends Employee{  
  10.       
  11.     @Column(name="pay_per_hour")  
  12.     private float pay_per_hour;  
  13.       
  14.     @Column(name="contract_duration")  
  15.     private String contract_duration;  
  16.   
  17.     public float getPay_per_hour() {  
  18.         return pay_per_hour;  
  19.     }  
  20.     public void setPay_per_hour(float payPerHour) {  
  21.         pay_per_hour = payPerHour;  
  22.     }  
  23.     public String getContract_duration() {  
  24.         return contract_duration;  
  25.     }  
  26.     public void setContract_duration(String contractDuration) {  
  27.         contract_duration = contractDuration;  
  28.     }  
  29. }  

Table structure for Employee class

table per concrete class 

Table structure for Regular_Employee class

table per concrete class 

Table structure for Contract_Employee class

table per concrete class
(3) Table Per Subclass:  In this strategy, tables are created as per class but related by foreign key. So there are no duplicate columns. We need to specify @Inheritance(strategy=InheritanceType.JOINED) in the parent class and @PrimaryKeyJoinColumnannotation in the subclasses.

File: Employee.java
  1. package com.javatpoint.mypackage;  
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name = "employee103")  
  6. @Inheritance(strategy=InheritanceType.JOINED)  
  7. public class Employee {  
  8. @Id  
  9. @GeneratedValue(strategy=GenerationType.AUTO)        
  10. @Column(name = "id")  
  11. private int id;  
  12.   
  13. @Column(name = "name")  
  14. private String name;  
  15.   
  16. //setters and getters  
  17. }  
File: Regular_Employee.java
  1. package com.javatpoint.mypackage;  
  2.   
  3. import javax.persistence.*;  
  4.   
  5. @Entity  
  6. @Table(name="regularemployee103")  
  7. @PrimaryKeyJoinColumn(name="ID")  
  8. public class Regular_Employee extends Employee{  
  9.       
  10. @Column(name="salary")    
  11. private float salary;  
  12.   
  13. @Column(name="bonus")     
  14. private int bonus;  
  15.   
  16. //setters and getters  
  17. }  
File: Contract_Employee.java
  1. package com.javatpoint.mypackage;  
  2.   
  3. import javax.persistence.*;  
  4.   
  5. @Entity  
  6. @Table(name="contractemployee103")  
  7. @PrimaryKeyJoinColumn(name="ID")  
  8. public class Contract_Employee extends Employee{  
  9.       
  10.     @Column(name="pay_per_hour")  
  11.     private float pay_per_hour;  
  12.       
  13.     @Column(name="contract_duration")  
  14.     private String contract_duration;  
  15.   
  16.     //setters and getters  
  17. }  

Table structure for Employee class

table per subclass class 

Table structure for Regular_Employee class

table per subclass class 

Table structure for Contract_Employee class

table per subclass class  
 One to one mapping: 
Employee.java
  1. package com.javatpoint;  
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name="emp220")  
  6. public class Employee {    
  7.       
  8.     @Id  
  9.     @GeneratedValue(strategy=GenerationType.AUTO)  
  10.     @PrimaryKeyJoinColumn  
  11. private int employeeId;    
  12. private String name,email;    
  13. @OneToOne(targetEntity=Address.class,cascade=CascadeType.ALL)  
  14. private Address address;  
  15. public int getEmployeeId() {  
  16.     return employeeId;  
  17. }  
  18. public void setEmployeeId(int employeeId) {  
  19.     this.employeeId = employeeId;  
  20. }  
  21. public String getName() {  
  22.     return name;  
  23. }  
  24. public void setName(String name) {  
  25.     this.name = name;  
  26. }  
  27. public String getEmail() {  
  28.     return email;  
  29. }  
  30. public void setEmail(String email) {  
  31.     this.email = email;  
  32. }  
  33. public Address getAddress() {  
  34.     return address;  
  35. }  
  36. public void setAddress(Address address) {  
  37.     this.address = address;  
  38. }    
  39.   
  40. }    
Address.java
  1. package com.javatpoint;  
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name="address220")  
  6. public class Address {    
  7.       
  8.     @Id  
  9.     @GeneratedValue(strategy=GenerationType.AUTO)  
  10. private int addressId;    
  11. private String addressLine1,city,state,country;    
  12. private int pincode;    
  13.   
  14. @OneToOne(targetEntity=Employee.class)  
  15. private Employee employee;  
  16. public int getAddressId() {  
  17.     return addressId;  
  18. }  
  19. public void setAddressId(int addressId) {  
  20.     this.addressId = addressId;  
  21. }  
  22. public String getAddressLine1() {  
  23.     return addressLine1;  
  24. }  
  25. public void setAddressLine1(String addressLine1) {  
  26.     this.addressLine1 = addressLine1;  
  27. }  
  28. public String getCity() {  
  29.     return city;  
  30. }  
  31. public void setCity(String city) {  
  32.     this.city = city;  
  33. }  
  34. public String getState() {  
  35.     return state;  
  36. }  
  37. public void setState(String state) {  
  38.     this.state = state;  
  39. }  
  40. public String getCountry() {  
  41.     return country;  
  42. }  
  43. public void setCountry(String country) {  
  44.     this.country = country;  
  45. }  
  46. public int getPincode() {  
  47.     return pincode;  
  48. }  
  49. public void setPincode(int pincode) {  
  50.     this.pincode = pincode;  
  51. }  
  52. public Employee getEmployee() {  
  53.     return employee;  
  54. }  
  55. public void setEmployee(Employee employee) {  
  56.     this.employee = employee;  
  57. }    
  58. }  

One to many mapping:  we will perform one-to-many association to map the list object of persistent class using annotation.
image.png
In such case, there can be many answers for a question and each answer may have its own information that is why we have used list in the persistent class (containing the reference of Answer class) to represent a collection of answers. 
Question.java
  1. package com.javatpoint;    
  2. import javax.persistence.*;  
  3. import java.util.List;    
  4.   
  5. @Entity  
  6. @Table(name="q5991")  
  7. public class Question {    
  8.   
  9. @Id   
  10. @GeneratedValue(strategy=GenerationType.TABLE)  
  11. private int id;    
  12. private String qname;    
  13.   
  14. @OneToMany(cascade = CascadeType.ALL)  
  15. @JoinColumn(name="qid")  
  16. @OrderColumn(name="type")  
  17. private List<Answer> answers;  
  18. public int getId() {  
  19.     return id;  
  20. }  
  21. public void setId(int id) {  
  22.     this.id = id;  
  23. }  
  24. public String getQname() {  
  25.     return qname;  
  26. }  
  27. public void setQname(String qname) {  
  28.     this.qname = qname;  
  29. }  
  30. public List<Answer> getAnswers() {  
  31.     return answers;  
  32. }  
  33. public void setAnswers(List<Answer> answers) {  
  34.     this.answers = answers;  
  35. }      
  36. }  
Answer.java
  1. package com.javatpoint;    
  2.       
  3.     import javax.persistence.*;  
  4.   
  5.     @Entity  
  6.     @Table(name="ans5991")  
  7.     public class Answer {   
  8.     @Id  
  9.     @GeneratedValue(strategy=GenerationType.TABLE)  
  10.       
  11.     private int id;    
  12.     private String answername;    
  13.     private String postedBy;  
  14.     public int getId() {  
  15.         return id;  
  16.     }  
  17.     public void setId(int id) {  
  18.         this.id = id;  
  19.     }  
  20.     public String getAnswername() {  
  21.         return answername;  
  22.     }  
  23.     public void setAnswername(String answername) {  
  24.         this.answername = answername;  
  25.     }  
  26.     public String getPostedBy() {  
  27.         return postedBy;  
  28.     }  
  29.     public void setPostedBy(String postedBy) {  
  30.         this.postedBy = postedBy;  
  31.     }      
  32.     }  

Many to One Mapping:

Employee.java

  1. package com.javatpoint;  
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name="emp107")  
  6. public class Employee {    
  7.      @Id  
  8.      @GeneratedValue(strategy=GenerationType.AUTO)    
  9. private int employeeId;    
  10. private String name,email;    
  11. @ManyToOne(cascade=CascadeType.ALL)  
  12. private Address address;  
  13. public int getEmployeeId() {  
  14.     return employeeId;  
  15. }  
  16. public void setEmployeeId(int employeeId) {  
  17.     this.employeeId = employeeId;  
  18. }  
  19. public String getName() {  
  20.     return name;  
  21. }  
  22. public void setName(String name) {  
  23.     this.name = name;  
  24. }  
  25. public String getEmail() {  
  26.     return email;  
  27. }  
  28. public void setEmail(String email) {  
  29.     this.email = email;  
  30. }  
  31. public Address getAddress() {  
  32.     return address;  
  33. }  
  34. public void setAddress(Address address) {  
  35.     this.address = address;  
  36. }    
  37. }  

Address.java

  1. package com.javatpoint;  
  2.   
  3. import javax.persistence.*;  
  4.   
  5. @Entity  
  6. @Table(name="address107")  
  7. public class Address {  
  8.     @Id  
  9.     @GeneratedValue(strategy=GenerationType.AUTO)  
  10.     private int addressId;    
  11.     private String addressLine1,city,state,country;    
  12.     private int pincode;    
  13.    @OneToOne(cascade=CascadeType.ALL)  
  14.     private Employee employee;  
  15.     public int getAddressId() {  
  16.         return addressId;  
  17.     }  
  18.     public void setAddressId(int addressId) {  
  19.         this.addressId = addressId;  
  20.     }  
  21.     public String getAddressLine1() {  
  22.         return addressLine1;  
  23.     }  
  24.     public void setAddressLine1(String addressLine1) {  
  25.         this.addressLine1 = addressLine1;  
  26.     }  
  27.     public String getCity() {  
  28.         return city;  
  29.     }  
  30.     public void setCity(String city) {  
  31.         this.city = city;  
  32.     }  
  33.     public String getState() {  
  34.         return state;  
  35.     }  
  36.     public void setState(String state) {  
  37.         this.state = state;  
  38.     }  
  39.     public String getCountry() {  
  40.         return country;  
  41.     }  
  42.     public void setCountry(String country) {  
  43.         this.country = country;  
  44.     }  
  45.     public int getPincode() {  
  46.         return pincode;  
  47.     }  
  48.     public void setPincode(int pincode) {  
  49.         this.pincode = pincode;  
  50.     }  
  51.     public Employee getEmployee() {  
  52.         return employee;  
  53.     }  
  54.     public void setEmployee(Employee employee) {  
  55.         this.employee = employee;  
  56.     }    
  57. }  

Many to Many mapping: We can map many to many relation either using list, set, bag, map, etc
Question.java
  1. package com.javatpoint;    
  2.     
  3. import java.util.List;  
  4. import javax.persistence.*;    
  5.     
  6. @Entity  
  7. @Table(name="ques1123")  
  8. public class Question {    
  9.     @Id  
  10.     @GeneratedValue(strategy=GenerationType.AUTO)  
  11. private int id;    
  12. private String qname;   
  13.   
  14. @ManyToMany(targetEntity = Answer.class, cascade = { CascadeType.ALL })  
  15. @JoinTable(name = "q_ans1123",   
  16.             joinColumns = { @JoinColumn(name = "q_id") },   
  17.             inverseJoinColumns = { @JoinColumn(name = "ans_id") })  
  18. private List<Answer> answers;  
  19.   
  20. public int getId() {  
  21.     return id;  
  22. }  
  23. public void setId(int id) {  
  24.     this.id = id;  
  25. }  
  26. public String getQname() {  
  27.     return qname;  
  28. }  
  29. public void setQname(String qname) {  
  30.     this.qname = qname;  
  31. }  
  32. public List<Answer> getAnswers() {  
  33.     return answers;  
  34. }  
  35. public void setAnswers(List<Answer> answers) {  
  36.     this.answers = answers;  
  37. }      
  38. }  
Answer.java
  1. package com.javatpoint;   
  2. import javax.persistence.*;  
  3.   
  4. @Entity  
  5. @Table(name="ans1123")  
  6. public class Answer {   
  7.       
  8.     @Id  
  9.     @GeneratedValue(strategy=GenerationType.AUTO)  
  10. private int id;    
  11. private String answername;    
  12. private String postedBy;    
  13. public int getId() {  
  14.     return id;  
  15. }  
  16. public void setId(int id) {  
  17.     this.id = id;  
  18. }  
  19. public String getAnswername() {  
  20.     return answername;  
  21. }  
  22. public void setAnswername(String answername) {  
  23.     this.answername = answername;  
  24. }  
  25. public String getPostedBy() {  
  26.     return postedBy;  
  27. }  
  28. public void setPostedBy(String postedBy) {  
  29.     this.postedBy = postedBy;  
  30. }  
  31.   
  32. }    

Hibernate Query Language (HQL): Hibernate offers a query language that embodies a very powerful and flexible mechanism to query, store, update, and retrieve objects from a database. This language, the Hibernate query Language (HQL), is an object-oriented extension to SQL. it doesn't depends on the table of the database. Instead of table name, we use class name in HQL. So it is database independent query language.

Advantage of HQL

There are many advantages of HQL. They are as follows:
  • database independent
  • supports polymorphic queries
  • easy to learn for Java Programmer

Query Interface

It is an object oriented representation of Hibernate Query. The object of Query can be obtained by calling the createQuery() method Session interface.
The query interface provides many methods. There is given commonly used methods:
  1. public int executeUpdate() is used to execute the update or delete query.
  2. public List list() returns the result of the ralation as a list.
  3. public Query setFirstResult(int rowno) specifies the row number from where record will be retrieved.
  4. public Query setMaxResult(int rowno) specifies the no. of records to be retrieved from the relation (table).
  5. public Query setParameter(int position, Object value) it sets the value to the JDBC style query parameter.
  6. public Query setParameter(String name, Object value) it sets the value to a named query parameter.

Example of HQL to get all the records

  1. Query query=session.createQuery("from Emp");//here persistent class name is Emp  
  2. List list=query.list();  

Example of HQL to get records with pagination

  1. Query query=session.createQuery("from Emp");  
  2. query.setFirstResult(5);  
  3. query.setMaxResult(10);  
  4. List list=query.list();//will return the records from 5 to 10th number  

Example of HQL update query

  1. Transaction tx=session.beginTransaction();  
  2. Query q=session.createQuery("update User set name=:n where id=:i");  
  3. q.setParameter("n","Udit Kumar");  
  4. q.setParameter("i",111);  
  5.   
  6. int status=q.executeUpdate();  
  7. System.out.println(status);  
  8. tx.commit();  

Example of HQL delete query

  1. Query query=session.createQuery("delete from Emp where id=100");  
  2. //specifying class name (Emp) not tablename  
  3. query.executeUpdate();  

HQL with Aggregate functions

You may call avg(), min(), max() etc. aggregate functions by HQL. Let's see some common examples:

Example to get total salary of all the employees

  1. Query q=session.createQuery("select sum(salary) from Emp");  
  2. List<Integer> list=q.list();  
  3. System.out.println(list.get(0));  

Example to get maximum salary of employee

  1. Query q=session.createQuery("select max(salary) from Emp");  

Example to get minimum salary of employee

  1. Query q=session.createQuery("select min(salary) from Emp");  

Example to count total number of employee ID

  1. Query q=session.createQuery("select count(id) from Emp");  

Example to get average salary of each employees

  1. Query q=session.createQuery("select avg(salary) from Emp"); 

HCQL (Hibernate Criteria Query Language)

The Hibernate Criteria Query Language (HCQL) is used to fetch the records based on the specific criteria. The Criteria interface provides methods to apply criteria such as retreiving all the records of table whose salary is greater than 50000 etc.

Advantage of HCQL

The HCQL provides methods to add criteria, so it is easy for the java programmer to add criteria. The java programmer is able to add many criteria on a query.

Criteria Interface

The Criteria interface provides many methods to specify criteria. The object of Criteria can be obtained by calling the createCriteria() method of Session interface.

Syntax of createCriteria() method of Session interface

  1. public Criteria createCriteria(Class c)  
The commonly used methods of Criteria interface are as follows:
  1. public Criteria add(Criterion c) is used to add restrictions.
  2. public Criteria addOrder(Order o) specifies ordering.
  3. public Criteria setFirstResult(int firstResult) specifies the first number of record to be retreived.
  4. public Criteria setMaxResult(int totalResult) specifies the total number of records to be retreived.
  5. public List list() returns list containing object.
  6. public Criteria setProjection(Projection projection) specifies the projection.

Restrictions class

Restrictions class provides methods that can be used as Criterion. The commonly used methods of Restrictions class are as follows:
  1. public static SimpleExpression lt(String propertyName,Object value) sets the less than constraint to the given property.
  2. public static SimpleExpression le(String propertyName,Object value) sets the less than or equal constraint to the given property.
  3. public static SimpleExpression gt(String propertyName,Object value) sets the greater than constraint to the given property.
  4. public static SimpleExpression ge(String propertyName,Object value) sets the greater than or equal than constraint to the given property.
  5. public static SimpleExpression ne(String propertyName,Object value) sets the not equal constraint to the given property.
  6. public static SimpleExpression eq(String propertyName,Object value) sets the equal constraint to the given property.
  7. public static Criterion between(String propertyName, Object low, Object high) sets the between constraint.
  8. public static SimpleExpression like(String propertyName, Object value) sets the like constraint to the given property.

Order class

The Order class represents an order. The commonly used methods of Restrictions class are as follows:
  1. public static Order asc(String propertyName) applies the ascending order on the basis of given property.
  2. public static Order desc(String propertyName) applies the descending order on the basis of given property.


Examples of Hibernate Criteria Query Language

There are given a lot of examples of HCQL.

Example of HCQL to get all the records

  1. Crietria c=session.createCriteria(Emp.class);//passing Class class argument  
  2. List list=c.list();  

Example of HCQL to get the 10th to 20th record

  1. Crietria c=session.createCriteria(Emp.class);  
  2. c.setFirstResult(10);  
  3. c.setMaxResult(20);  
  4. List list=c.list();  

Example of HCQL to get the records whose salary is greater than 10000

  1. Crietria c=session.createCriteria(Emp.class);  
  2. c.add(Restrictions.gt("salary",10000));//salary is the propertyname  
  3. List list=c.list();  

Example of HCQL to get the records in ascending order on the basis of salary

  1. Crietria c=session.createCriteria(Emp.class);  
  2. c.addOrder(Order.asc("salary"));  
  3. List list=c.list();  

HCQL with Projection

We can fetch data of a particular column by projection such as name etc. Let's see the simple example of projection that prints data of NAME column of the table only.
  1. Criteria c=session.createCriteria(Emp.class);  
  2. c.setProjection(Projections.property("name"));  
  3. List list=c.list();  

Hibernate Named Query

The hibernate named query is way to use any query by some meaningful name. It is like using alias names. The Hibernate framework provides the concept of named queries so that application programmer need not to scatter queries to all the java code. 

Hibernate Named Query by annotation

If you want to use named query in hibernate, you need to have knowledge of @NamedQueries and @NamedQuery annotations.
@NameQueries annotation is used to define the multiple named queries.
@NameQuery annotation is used to define the single named query.
Let's see the example of using the named queries:
  1. @NamedQueries(  
  2.     {  
  3.         @NamedQuery(  
  4.         name = "findEmployeeByName",  
  5.         query = "from Employee e where e.name = :name"  
  6.         )  
  7.     }  
  8. )  
  1. Employee.java

    It is a persistent class that uses annotations to define named query and marks this class as entity.
    1. package com.javatpoint;  
    2.   
    3. import javax.persistence.*;  
    4. import javax.persistence.Entity;  
    5. import javax.persistence.GeneratedValue;  
    6. import javax.persistence.Id;  
    7.   
    8. @NamedQueries(  
    9.     {  
    10.         @NamedQuery(  
    11.         name = "findEmployeeByName",  
    12.         query = "from Employee e where e.name = :name"  
    13.         )  
    14.     }  
    15. )  
    16.   
    17. @Entity  
    18. @Table(name="em")  
    19. public class Employee {  
    20.       
    21.     public String toString(){return id+" "+name+" "+salary+" "+job;}  
    22.       
    23.     int id;  
    24.     String name;  
    25.     int salary;  
    26.     String job;  
    27.     @Id  
    28.     @GeneratedValue(strategy=GenerationType.AUTO)  
    29.        
    30.     //getters and setters  
    31. }  

FetchData.java

It is a java class that uses the named query and prints the informations based on the query. The getNamedQuery method uses the named query and returns the instance of Query.
  1. package com.javatpoint;    
  2.     
  3. import java.util.*;  
  4. import javax.persistence.*;  
  5. import org.hibernate.*;  
  6. import org.hibernate.boot.Metadata;  
  7. import org.hibernate.boot.MetadataSources;  
  8. import org.hibernate.boot.registry.StandardServiceRegistry;  
  9. import org.hibernate.boot.registry.StandardServiceRegistryBuilder;  
  10.     
  11. public class Fetch {    
  12. public static void main(String[] args) {    
  13.     
  14.      StandardServiceRegistry ssr=new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();  
  15.         Metadata meta=new MetadataSources(ssr).getMetadataBuilder().build();  
  16.           
  17.         SessionFactory factory=meta.getSessionFactoryBuilder().build();  
  18.         Session session=factory.openSession();  
  19.                     
  20.     //Hibernate Named Query    
  21.            TypedQuery query = session.getNamedQuery("findEmployeeByName");    
  22.             query.setParameter("name","amit");   
  23.                     
  24.             List<Employee> employees=query.getResultList();   
  25.             
  26.     Iterator<Employee> itr=employees.iterator();    
  27.      while(itr.hasNext()){    
  28.     Employee e=itr.next();    
  29.     System.out.println(e);    
  30.      }    
  31.     session.close();     
  32.   }    
  33. }    


Derived properties: The properties that are not mapped to a column, but calculated at runtime by evaluation of an expression are called derived properties. The expression can be defined using the formula attribute of the element.

Difference between get and load method of session in Hibernate:  Hibernate Session  class provides two method to access object e.g. session.get() and session.load(). Main difference between get() vs load method is that get() involves database hit if object doesn't exists in Session Cache and returns a fully initialized object which may involve several database call while load method can return proxy in place and only initialize the object or hit the database if any method other than getId() is called on persistent or entity object. This lazy initialization can save couple of database round-trip which result in better performance.
another difference between get and load which is worth remembering. get method of Hibernate Session class returns null if object is not found in cache as well as on database while load() method throws ObjectNotFoundException if object is not found on cache as well as on database but never return null. Means Only use the load() method if you are sure that the object exists. If you are not sure that the object exists, then use one of the get() methods.
//Example of calling get method of Hiberante Session class
Session session = SessionFactory.getCurrentSession();
Employee Employee = (Employee) session.get(Employee.class, EmployeeID);
//Example of calling load method of Hiberante Session
Session session = SessionFactory.getCurrentSession();
Employee Employee = (Employee) session.load(Employee.class, EmployeeID);
 Difference between save and saveOrUpdate in Hibernate:  Main difference between save and saveOrUpdate method is that save() generates a new identifier and INSERT record into database while saveOrUpdate can either INSERT or UPDATE based upon existence of record. Clearly saveOrUpdate is more flexible in terms of use but it involves an extra processing to find out whether record already exists in table or not. In summary  save() method saves records into database by INSERT SQL query, Generates a new identifier and return the Serializable identifier back. On the other hand  saveOrUpdate() method either INSERT or UPDATE based upon existence of object in database. If persistence object already exists in database then UPDATE SQL will execute and if there is no corresponding object in database than INSERT will run.

What is the difference between merge and update methods of Session Object?
Use update() if you are sure that the session does not contain an already persistent instance with the same identifier, and merge() if you want to merge your modifications at any time without consideration of the state of the session. 
Difference between save and persist method in Hibernate:
  1. First difference between save and persist is there return type. Similar to save method persist also INSERT records into database but return type of persist is void while return type of save is Serializable object.  
  2. Another difference between persist and save is that both methods make a transient instance persistent. However, persist() method doesn't guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen at flush time.
  3. One more thing which differentiate persist and save method in Hibernate is that is there behavior on outside of transaction boundaries. persist() method guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries. save() method does not guarantee the same, it returns an identifier, and if an INSERT has to be executed to get the identifier (e.g. "identity" generator), this INSERT happens immediately, no matter if you are inside or outside of a transaction.
  4. Fourth difference between save and persist method in Hibernate is related to previous difference on save vs persist. Because of its above behavior of persist method outside transaction boundary, its useful in long-running conversations with an extended Session context. On the other hand save method is not good in a long-running conversation with an extended Session context.
What is named SQL query in Hibernate?
Named queries are SQL queries which are defined in mapping document using <sql-query> tag and called using Session.getNamedQuery() method. Named query allows you to refer a particular query by the name you provided, by the way you can define named query in hibernate either by using annotations or xml mapping file. @NameQuery is used to define single named query and @NameQueries is used to define multiple named query in hibernate.
<sql-query name = "empdetails">
   <return alias="emp" class="com.test.Employee"/>
      SELECT emp.EMP_ID AS {emp.empid},
                 emp.EMP_ADDRESS AS {emp.address},
                 emp.EMP_NAME AS {emp.name
      FROM Employee EMP WHERE emp.NAME LIKE :name
</sql-query>

Invoke Named Query :
List people = session.getNamedQuery("empdetails").setString("TomBrady", name).setMaxResults(50).list();

What is difference between sorted and ordered collection in hibernate?
A sorted collection is sorted in memory by using Java Comparator, while a ordered collection uses database's order by clause for ordering. For large data set it's better to use ordered collection to avoid any OutOfMemoryError in Java, by trying to sort them in memory.

Define cascade and inverse option in one-many mapping?
cascade - enable operations to cascade to child entities.
cascade="all|none|save-update|delete|all-delete-orphan"

inverse - mark this collection as the "inverse" end of a bidirectional association.
inverse="true|false" 
Essentially "inverse" indicates which end of a relationship should be ignored, so when persisting a parent who has a collection of children, should you ask the parent for its list of children, or ask the children who the parents are? 

What is difference between transient, persistent and detached object in Hibernate?
In Hibernate, Object can remain in three state transient, persistent or detached.  
  • Persistent objects and collections are short lived single threaded objects, which store the persistent state. These objects  synchronize their state with the database depending on your flush strategy (i.e. auto-flush where as soon as setXXX() method is called or an item is removed from a Set, List  etc or define your own synchronization points with session.flush(), transaction.commit() calls). If you remove an item  from a persistent collection like a Set, it will be removed from the database either immediately or when flush() or commit() is called depending on your flush strategy. They are Plain Old Java Objects (POJOs) and are currently associated with a session. As soon as the associated session is closed, persistent objects become detached objects and are free to use directly as data transfer objects in any application layers like business layer, presentation layer etc.   
  • Detached objects and collections are instances of persistent objects that were associated with a session but currently not associated with a session. These objects can be freely used as Data Transfer Objects without having any impact on your database. Detached objects can be later on attached to another session by calling methods like session.update(), session.saveOrUpdate() etc. and become persistent objects.
  • Transient objects and collections are instances of persistent objects that were never associated with a session. These objects can be freely used as Data Transfer Objects without having any impact on your database. Transient objects become persistent objects when associated to a session by calling methods like session.save( ), session.persist( )  etc.

Q. What are the benefits of detached objects? 
A. 
Pros: When long transactions are required due to user think-time, it is the best practice to break the long transaction up into two or more transactions. You can use detached objects from the first transaction to carry data all the way up to the presentation layer. These detached objects get modified outside a transaction and later on re-attached to a new transaction via another session.

Cons: In general, working with detached objects is quite cumbersome, and it is better not to clutter up the session with them if possible. It is better to discard them and re-fetch them on subsequent requests. This approach is not only more portable but also more efficient because - the objects hang around in Hibernate's cache anyway.
Also from pure rich domain driven design perspective, it is recommended to use DTOs (DataTransferObjects) and DOs (DomainObjects) to maintain the separation between Service and UI tiers.

Q. How does Hibernate distinguish between transient (i.e. newly instantiated) and detached objects? 
A. 
  • Hibernate uses the "version" property, if there is one.
  • If not uses the identifier value. No identifier value means a new object. This does work only for Hibernate managed surrogate keys. Does not work for natural keys and assigned (i.e. not managed by Hibernate) surrogate keys.
  • Write your own strategy with Interceptor.isUnsaved( ).
Note: When you reattach detached objects, you need to make sure that the dependent objects are reattached as well. 

Caching in Hibernate:

Hibernate caching improves the performance of the application by pooling the object in the cache. It is useful when we have to fetch the same data multiple times.
There are mainly two types of caching: first level cache and second level cache.

First Level Cache

Session object holds the first level cache data. It is enabled by default. The first level cache data will not be available to entire application. An application can use many session object.
Second Level Cache
SessionFactory object holds the second level cache data. The data stored in the second level cache will be available to entire application. But we need to enable it explicitely.
What is Second level Cache in Hibernate?
Hibernate uses two different caches for objects: first-level cache and second-level cache. First-level cache is associated with the Session object, while second-level cache is associated with the SessionFactory object. By default, Hibernate uses first-level cache on a per-transaction basis. Hibernate uses this cache mainly to reduce the number of SQL queries it needs to generate within a given transaction. For example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE statement at the end of the transaction, containing all the modifications. The second-level cache needs to be explicitly configured. Hibernate provides a flexible concept to exchange cache providers for the second-level cache. By default Ehcache is used as caching provider. However more sophisticated caching implementation can be used like the distributed JBoss Cache or Oracle Coherence.

The Hibernate configuration looks like:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
The ehcache.xml can be configured to cache objects of type com.myapp.Order as shown below
<cache name="com.myapp.Order"
   maxElementsInMemory="300"
   eternal="true"
   overflowToDisk="false"
   timeToIdleSeconds="300"
   timeToLiveSeconds="300"
   diskPersistent="false"
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU"      
/>
second-level cache reduces the database traffic by caching loaded objects at the SessionFactory level between transactions. These objects are available to the whole application, not just to the user running the query. The 'second-level' cache exists as long as the session factory is alive. The second-level cache holds on to the 'data' for all properties and associations (and collections if requested) for individual entities that are marked to be cached. It is imperative to implement proper cache expiring strategies as caches are never aware of changes made to the persistent store by another application. he following are the list of possible cache strategies. 
  1. Read-only: This is useful for data that is read frequently, but never updated. This is the most simplest and best-performing cache strategy.
  2. Read/write: Read/write caches may be appropriate if your data needs to be updated. This carry more overhead than read-only caches. In non-JTA environments, each transaction should be completed when session.close() or session.disconnect() is called.
  3. Nonstrict read/write: This is most appropriate for data that is read often but only occasionally modified.This strategy does not guarantee that two transactions won't simultaneously modify the same data. 
  4. Transactional: This is a fully transactional cache that may be used only in a JTA environment.
It can be enabled via the Hibernate mapping files as shown below:
<class name="com.myapp.Order">
    <cache usage="read-write"/>
    ....
</class>

Q. How does the hibernate second-level cache work?
A. Hibernate always tries to first retrieve objects from the session and if this fails it tries to retrieve them from the second-level cache. If this fails again, the objects are directly loaded from the database. Hibernate's static initialize() method, which populates a proxy object, will attempt to hit the second-level cache before going to the database. The Hibernate class provides static methods for manipulation of proxies. 

public final class Hibernate extends Object {
    ....
 public static void initialize(Object proxy)  throws HibernateException 
    .... 
}

As a consequence of using the Hibernate second-level cache, you have to be aware of the fact that each call of a data access method can either result in a cache hit or miss. So, configure your log4j.xml to log your hits and misses.
<logger name="org.hibernate.cache">
   <level value="DEBUG" />
</logger>

Alternatively, you can use Spring AOP to log the cache access on your DAO methods. 
The second level cache is a powerful mechanism for improving performance and scalability of your database driven application. Read-only caches are easy to handle, while read-write caches are more subtle in their behavior. Especially, the interaction with the Hibernate session can lead to unwanted behavior.

What is query cache in Hibernate ?
The query cache is responsible for caching the results and to be more precise the keys of the objects returned by queries. Let us have a look how Hibernate uses the query cache to retrieve objects. In order to make use of the query cache we have to modify the person loading example as follows.
Query query = session.createQuery("from Order as o where o.status=?");
query.setInt(0, "Active");
query.setCacheable(true); // the query is cacheable
List l = query.list();

You also have to change the hibernate configuration to enable the query cache. This is done by adding the following line to the Hibernate configuration.
<property name="hibernate.cache.use_query_cache">true</property>

Q. What are the pitfalls of second level and query caches?
A. Memeory is a finite resource, and over use or incorrect useage like cacheing the Order object and all its referenced objects can cause OutOfMemoryError. Here are some tips to overcome the pitfalls relating to cacheing.
1. Set entity’s keys as query parameters, rather than setting the entire entity object. Critreia representations should also use identifiers as parameters. Write HQL queries to use identifiers in any substitutable parameters such as WHERE clause, IN clause etc.
In the example below, the entire customer and everything he/she references would be held in cache until either the query cache exceeds its configured limits and it is evicted, or the table is modified and the results become dirty.
final Customer customer = ... ;
final String hql = "FROM Order as order WHERE order.custOrder = ?"
final Query q = session.createQuery(hql);
q.setParameter(0, customer);
q.setCacheable(true);

Instead of setting the whole customer object as shown above, just set the id. 
final Order customer = ... ;
final String hql = "from Order as order where order.cusomer.id = ?"
final Query q = session.createQuery(hql);
q.setParameter(0, customer.getId());
q.setCacheable(true);

2. Hibernate's query cache implementation is pluggable by decorating Hibernate's query cache implementation. This involves overriding the put( ) method to check if a canonical equivalent of a query results object already exist in the Object[][], and assign the same QueryKey if it exists. 
3. If you are in a single JVM using in memory cache only, use hibernate.cache.use_structured_entries=false in your hibernate configuration. 

Here are some general performance tips:
1. Session.load will always try to use the cache. Session.find does not use the cache for the primary object, but cause the cache to be populated. Session.iterate always uses the cache for the primary object and any associated objects.
2. While developing, enable the show SQL and monitor the generated SQL. 
<property name="show_sql">true</property>

Also enable the "org.hibernate.cache" logger in your log4j.xml to monitor cache hits and misses.

Can we make an Hibernate Entity Class final?
Yes, you can make an Hibernate Entity class final, but that's not a good practice. Since Hibernate uses proxy pattern for performance improvement in case of lazy association, by making an entity final, Hibernate will no longer be able to use proxy, because Java doesn't allow extension of final class, thus limiting your performance improvement options. Though, you can avoid this penalty, if your persistent class is an implementation of interface, which declares all public methods defined in Entity class.

Why it's important to provide no argument constructor in Hibernate Entities?
Every Hibernate Entity class must contain a no argument constructor, because Hibernate framework creates instance of them using Reflection API, by calling Class.newInstance() method. This method will throw InstantiationException if it doesn't found no argument constructor inside Entity class.

Criteria API: Criteria is a simplified API for retrieving entities by composing Criterion objects. This is a very convenient approach for functionality like "search" screens where there is a variable number of conditions to be placed upon the result set.
List employees = session.createCriteria(Employee.class)
         .add(Restrictions.like("name", "a%") )
         .add(Restrictions.like("address", "Boston"))
 .addOrder(Order.asc("name") )
 .list();

Q. How does hibernate support lazy loading?
A. Hibernate uses a proxy object to support lazy loading. Basically as soon as you reference a child or lookup object via the accessor/getter methods, if the linked entity is not in the session cache (i.e. the first-level cache), then the proxy code will go off to the database and load the linked object. It uses javassist (or CGLIB ) to effectively and dynamically generate sub-classed implementations of your objects.
Let's look at an example. An employee hierarchy table can be represented in a database table as shown below 

public class Employee {
   private Long id;
   private String name;
   private String title;
   private Employee superior;
   private Set<Employee> subordinates;
   //getters and setters are omitted
}
In the above example, if you use lazy loading then the "superior" and "subordinates" will be proxied (i.e. not the actual object, but the stub object that knows how to load the actual object) when the main "Employee" object is loaded. So, if you need to get the "subordinates" or "superior" object, you invoke the getter method on the employee likeemployee.getSuperior( ) and the actual object will be loaded.

Q. What are some of the pitfalls of using a proxy object?
A. The typical pitfall is in how you implement your equals( ) method that gets invoked when comparing objects.

Pitfall 1: As explained before, the proxy objects are dynamically created by sub-classing your object at runtime. The subclass will have all the methods of the parent, but the fields (e.g. name, etc) in the proxy object will remain null, and when any of the methods are accessed via getter/setter method, the proxy loads up the real object from the database.
A typical equals( ) method implementation will look like
@Override
public boolean equals(Object obj) {
  if (obj == null) {
    return false;
  }
  if (obj == this) {
    return true;
  }
  if (!(obj instanceof Employee)) {         //Line X: compare object type
    return false;
  }
  return name.equals((Employee)obj).name);  //Line Y: compare names
}
As discussed before, the supplied object is a proxy object and the supplied name will be null. This can be fixed by using the getter method in Line Y instead of using the field directly. Using the getter method will tell the proxy object to load the actual object as shown below. 
@Override
public boolean equals(Object obj) {
  if (obj == null) {
    return false;
  }
  if (obj == this) {
    return true;
  }
  if (!(obj instanceof Employee)) {
    return false;
  }
  return name.equals((Employee)obj).getName());  //Line Y: compare names
}
Pitfall 2: We saw earlier that the the proxy objects are dynamically created by sub-classing your object. In a simple scenario where you only have the "Employee" object the typecasting in Line Y and "instanceof" operator in Line X will work. But, what will happen if you have a type hierarchy for The class Employee as shown below
public class PermanentEmployee extends Employee {
    .......
}

public class CasualEmployee extends Employee {
    .......
}

When you have a type hierarchy as shown above, the type casts and instanceof operators will not work with the proxy objects. To prevent this issue, you have two approaches.
Approach 1: Switch of proxying on the top level class by setting lazy=”false”, which will turn proxying off for the hierachy.
Approach 2: Use the "Gang of Four" (i.e. GoF) visitor design pattern that allows you to adapt a single object or manipulate a collection of polymorphic objects without all the messy typecasts and instanceof operations.

Pitfall 3: As per the above example, if you have an “Employee” class, that contains a “name” property, when you invoke do “employee.getName()”, the proxies will get the "name" from Hibernate caches (either 1st or 2nd levels) or the database when requested. But if this call happens in the presentation layer like in the Struts action class, you will get the org.hibernate.LazyInitializationException because the Hibernate Session is closed and this lazy attribute does not have the session attached, hence  can’t load their lazy references.
The solution is to de-proxy the employee class as shown below:
Step 1: Write a generic utility class to de-proxy a given object
public class HibernateUtil {
    public static <T> T unproxy(T entity) {
        if (entity == null) {
            return null;
        }
        if (entity instanceof HibernateProxy) {
            Hibernate.initialize(entity);
            entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
        }
        return entity;
    }
}
Step 2: Use the above utility class?
     public Employee getSuperior() {
             superior = HibernateUtils.unproxy(employee);
             return superior;
     } 
These types of issues are hard to debug, and being aware of these pitfalls can save you lots of time in debugging and fixing the issues. 
HibernateTemplate:  org.springframework.orm.hibernate.HibernateTemplate is a helper class which provides different methods for querying/retrieving data from the database. It also converts checked HibernateExceptions into unchecked DataAccessExceptions.

Benefits of HibernateTemplate:
  • HibernateTemplate, a Spring Template class simplifies interactions with Hibernate Session.
  • Common functions are simplified to single method calls.
  • Sessions are automatically closed.
  • Exceptions are automatically caught and converted to runtime exceptions.

Hibernate Supported Databases:Hibernate supports almost all the major RDBMS. Following is list of few of the database engines supported by Hibernate.
  • HSQL Database Engine
  • DB2/NT
  • MySQL
  • PostgreSQL
  • FrontBase
  • Oracle
  • Microsoft SQL Server Database
  • Sybase SQL Server
  • Informix Dynamic Server
List of various important databases dialect property type:

Database
Dialect Property
DB2org.hibernate.dialect.DB2Dialect
HSQLDBorg.hibernate.dialect.HSQLDialect
HypersonicSQLorg.hibernate.dialect.HSQLDialect
Informixorg.hibernate.dialect.InformixDialect
Ingresorg.hibernate.dialect.IngresDialect
Interbaseorg.hibernate.dialect.InterbaseDialect
Microsoft SQL Server 2000  org.hibernate.dialect.SQLServerDialect
Microsoft SQL Server 2005 org.hibernate.dialect.SQLServer2005Dialect
Microsoft SQL Server 2008 org.hibernate.dialect.SQLServer2008Dialect
MySQLorg.hibernate.dialect.MySQLDialect
Oracle (any version)org.hibernate.dialect.OracleDialect
Oracle 11gorg.hibernate.dialect.Oracle10gDialect
Oracle 10gorg.hibernate.dialect.Oracle10gDialect
Oracle 9iorg.hibernate.dialect.Oracle9iDialect
PostgreSQLorg.hibernate.dialect.PostgreSQLDialect
Progressorg.hibernate.dialect.ProgressDialect
SAP DBorg.hibernate.dialect.SAPDBDialect
Sybaseorg.hibernate.dialect.SybaseDialect
Sybase Anywhereorg.hibernate.dialect.SybaseAnywhereDialect

Comments

Popular posts from this blog

Ramoji Film City, Hyderabad, India

Ashtavinayak Temples | 8 Ganpati Temples of Maharashtra | Details Travel Reviews