Object relationship mapping and hibernate


Published on

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Object relationship mapping and hibernate

  1. 1. Object Relationship Mapping (ORM) ORM stands for Object relational Mapping. ORM is an attempt to map the notion of object and relational world so that they can talk to each other in a easy way. Any non trivial application has a database behind it and Java applications are no exception. In fact if we look closely into any application, one will realize that the application gets more or less modeled around the data model. In database technology, relational database are the clear winners. Other database technologies has come and gone. Relational concept of data management was first introduced by E.F. Codd in 1970. An analogy for relational model can be drawn with spreadsheets. Each sheet represents a table and the columns in the sheet represent the table attributes. Each instance of data is represented by the rows. The data in different sheets are connected with each other by referring to the data point using the sheet number, column number and row number. This is what is called as foreign key relationship in database technology. In fact most of the GUI interfaces to database show the data in a spreadsheet format. To interact with the database, Standard Query Language(SQL) has emerged as the standard way. The SQL standards are controlled by ANSI. However there are still proprietary variations to it. SQL provides two types of mechanism:Data Definition Language (DDL) : Provides ways to create and alter tables.Data Manipulation Language (DML) : Provides ways to manipulate and retrieve data. It includesinserting, updating and deleting data. To interact with the database, the applications has to issue SQL to the database. How to issue SQL is proprietary to each database. They have their own APIs exposed for this and the APIs might be written in different languages. For example a database written in C language. might expose C based APIs. Considering that the data independence is considered a virtue for any application, it would be a lot of work for an application developer to understand the interfaces for each of the database and implement it. To solve this kind of porblem, Java has come up with ((JDBC)) APIs. JDBC is the most popular way of connecting to databases in Java. Its an interface based API where the implementation for each database is provided by the drivers for particular database. Though JDBC is very popular, it is inherently relational in nature. The basic problem is the mismatch in conceptual level between relational technology and Object Oriented Technology. Java being a pure Object
  2. 2. Oriented Language, this mismatch is important to deal with. This mismatch is also known as Objectrelational mismatch. ORM tries to solve this mismatch.Lets see the kind of mismatch that are there:InheritanceJava supports inheritance. For example we might have User class from which Student and Teacherclass is derived.Userpublic class User{private String Name;//Setters and getters}Studentpublic class Student extends User{private double percentage;//Setter and Getter}Teacherpublic class Teacher extends User{private int exprienceYears;//Setters and Getters}Now think for a moment how you are going to map these classes to the table structure. ORMframeworks adopt different strategies to solve this, which can be seen at ((Hibernate)) section.
  3. 3. Also with this comes the mismatch in terms of polymorphism. A reference of User type can refer to anobject of Student or Teacher. Also a list might contain a mix of Teacher, Student and User objects.How you build those list by querying database. The ORM frameworks has to somehow differentiatethat the data is belonging to User or Student or Teacher.GranularityThe granularity problem comes when the number of classes mapping to number of tables in thedatabase do not match. For example lets say we have the User class which has an Address objectpublic class User{private String Name;private Address address;//Setters and getters}Addresspublic class Address{private String city;private String country;//Setters and gettersAlso the table structure for User isTable USER:NAMECITYCOUNTRYThere is one table but the data is sitting in two objects. The same problem can come the other wayround also where you have two tables and one class containing all the data points. ORM frameworkshas to care of this mismatch in terms of different number of tables mapped to different number ofclasses.
  4. 4. Identity and EqualityThe notion of identity is driven by primary key in relational model. Given a primary key you will alwaysretrieve the same data. Also it does not matter, how many clients are retrieving the same data. Withright isolation level all will see the same data. In Java the situation becomes more complex. The samedata row might be represented by more objects in Java layer. For example a User data in databasewith primary key 1 might have more than one object in different thread. The question comes which isthe object having the right data. Also if all thread try to save the same object, than who wins? Similarproblem arises related to equality. In Java the default is reference equality. If the references arepointing to the same object than they are equal. The corollary is that if there are two objectsrepresenting the same data row, they will come out as different. To solve this we have to giveimplementation to the equals methos, but its not always trivial. ORM solutions has to provideprovisions to maintain the correct notion of equality and identity. The frameworks usually ask toexplicitly map the primary key to an attribute.AssociationIn Java the relationship is done by association. For example User has a reference of address. Howeverin Tables, the relationship is done with foreign key association. Java has also the notion ofdirectionality. For example you can access address form User but not the other way round. To buildthe relationship from both side you have to put the reference on both the sides.Userpublic class User{private Address address;//Setters and Getters}Addresspublic class Address{private User user;//setters and getters}
  5. 5. However there is no notion of directionality in the relational world.The foreign key relationship can bedone at any one end and the relationship is build. With SQL you can navigate from any end. Forexample the foreign key relationship build at User side will beTable ADDRESSADDRESS_IDCITYCOUNTRYTable USERUSER_IDNAMEADDRESS_ID (Fk)ORM solutions has to deal with these association while setting and getting the data from the database.Type SystemsObject Oriented and relational world has different type systems. For example in relational world stringcan be constrained on the size however on the Java side you can point the reference of String to anysize based on memory allocated. Also date and times are handled differently in Java and relationalworld. For example in some databases there is a distinction between date, time and timestamp. Timestamp contains both date and time. In Java, the date is a long value which contains the date and timeboth. So when you fetch the date or time from relational world how you map it to a Java data type ofDate or Calendar.Databases are DifferentThere are so many popular databases in the market. In spite of SQL being a standard, there are stillvariations in the SQL support in each database and there are many vendor extensions and individualflavors in each database. Though this is not really an ORM issue but it is important from theperspective of database portability, if you are looking for it. Ensuing database portability using JDBC isusually a hurricane task if you wish to use the individual flavors of database for performance or otherreasons. ORM frameworks attempt to handle most of the important databases transparently. Also theydo have extension mechanisms if you wish to support another database
  6. 6. A video explaining the above concepts: ORM frameworks adopt different strategies to solve these kind of mismatches. ORM frameworks strive to preserve the notion of object world concepts and shield the developers from relational world by taking care of mappings. This should be taken as an excuse to not to learn relational concepts. In fact on the other way to be a good user of ORM frameworks, one should understand how the mapping works and the implications of it. The number issue in using ORM frameworks is performance and most of the time its because of not understanding how the ORM frameworks map to the relational world and not having a good grasp of relational world concepts. Hibernate Introduction Hibernate is an ORM framework. It provides capability to interact with database in an object oriented way. Hibernate provides its own HQL (Hibernate query language) also. The concepts of ORM are now adopted in EJB3.0 in the form of entity beans and Jave Persistence API (JPA). Hibernate supports Entity beans also. This means hibernate can act as an implementation provider for Entity beans. In fact, JBoss uses hibernate as implementation provider for Entity beans. Hibernate has its own set of APIs also which at the moment are richer than JPA. Going forward however we might see Entity beans and JPA closing this gap. Lets make a Java project where we will persist the data into the database. First download the Hibernate Core from https://www.hibernate.org/6.html. Unzip the download at a location and you will find the following important directories/file in it (This might be different from what you see as hibernate keeps on changing the structure).doc - contains the reference document for hibernateeg - example applicationetc - configuration filesgrammerlib - contains dependencies for hibernate. See lib/_README.txt for details about libraries.src - source code of hibernatetest - test suite
  7. 7. hibernate3.jar - hibernate library Make a simple Java application in your IDE. Have the following libraries in the build path: From Hibernate Core (<hibernate-distribution-*>/lib/required)antlr-2.7.6commons-collections-3.1.jardom4j-1.6.1.jarjavassist-3.9.0.GA.jarjta-1.1.jarslf4j-api-1.5.8.jar<hibernate-distribution-*>/lib/ -Choose between cglib or javassist<hibernate-distribution>/*hibernate3.jar Download slf4j from http://www.slf4j.org/dist/slf4j-simple-1.5.8.jarhsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar. Hibernate is a Object relational mapping framework. What it will help us is in saving the objects into the relational world. So lets have our Java class whose object instances at runtime will be saved by hibernate to the database. public class Student { //Id will correspond the primary key in the database private Long id; protected String name; public Long getId() { return id; } public void setId(Long id) {this.id = id;} public String getName() {return name;} public void setName(String name) {this.name = name;} }
  8. 8. Now we have the domain class definition with us. Now we will put a mapping file which will map thisclass to the data model in the database. We are not creating the table in the database as we will usehibernate to generate the data model. Though in real life application you would have your data modelalready created and placed in the database.Student.hbm.xml (Put it together with Student class)<?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><!-- class attributes -name - Java class nametable - Table to which this class is mappedschema - The schema where it sitsid -name - name of property on Java class. It will result in getId() and setId methodcolumn - column in table to which it is mappedgenerator- how the ids to be generated--><class name="com.oyejava.Student" table="Student" schema="PUBLIC"><id name="id" column="STUDENT_ID"><generator class="increment"/></id><!-- name - name of property in Java class. getName() and setName()column - column in table to which it is mapped. --><property name="name" column="NAME" /></class></hibernate-mapping>Now we will provide hibernate the details to connect to the database. Similar to JDBC coding, theconnection details and drivers need to be provided to Hibernate. We will use hsql, the details of which
  9. 9. can be seen at HypersonicThis is done in a XML file.hibernate.cfg.xml (Put it in the class path)<?xml version=1.0 encoding=utf-8?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- Database connection settings --><!-- If the below drive does not works try org.hsqldb.jdbc.JDBCDriver--><property name="connection.driver_class">org.hsqldb.jdbcDriver</property><property name="connection.url">jdbc:hsqldb:hsql://localhost</property><property name="connection.username">sa</property><property name="connection.password"></property><!-- JDBC connection pool (use the built-in) --><property name="connection.pool_size">1</property><!-- SQL dialect - This tells the SQL grammer to be used --><property name="dialect">org.hibernate.dialect.HSQLDialect</property><!-- Enable Hibernates automatic session context management --><property name="current_session_context_class">thread</property><!-- Disable the second-level cache --><property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property><!-- Log out all the sql that hibernate is issuing to datbase.This is very useful for debugging --><property name="show_sql">true</property><!-- Create the table looking at class and mapping. Very useful in developmentUse validate in production environments. --><property name="hbm2ddl.auto">create</property>
  10. 10. <!-- Mapping file. --><mapping resource="com/oyejava/Student.hbm.xml"/></session-factory></hibernate-configuration>Now we will write a utility class which will start the session factory of hibernate, if it is not started andwill return the Session factory. This is the most used pattern of boot strapping Hibernate. Sessionfactory contains all the configuration information at runtime. A Session is retrieve from the Sessionfactory. A session is a light weight object which provide services to interact with database. You canthink of Session like JDBC connection, thought it may not open the database connection if notrequired.HibernateUtilpublic class HibernateUtil {private static SessionFactory sessionFactory;static{try{//By default it will look for hibernate.cfg.xml in the class pathsessionFactory=new Configuration().configure().buildSessionFactory();}catch(Throwable ex){throw new ExceptionInInitializerError(ex);}}public static SessionFactory getSessionFactory(){return sessionFactory;}public static void shutdown(){//Close caches and connection poolgetSessionFactory().close();}
  11. 11. }Now lets write the main class in which we will create a Student object and persist it to databasepublic class HibernateBasic {public static void main(String[] args) {//Get the session from the Session factorySession session = HibernateUtil.getSessionFactory().openSession();Transaction tx= session.beginTransaction();Student student = new Student();student.setName("oyeJava");Long studentId = (Long)session.save(student);System.out.println(studentId);tx.commit();session.close();}}Run the application and check in the database. It should persist a row of data. Download the sourcecode from down below in the attachment section. The libraries has to be included as per the list givenabove.In the above example we saw how to configure hibernate using XML mapping. The present trend ishowever to move towards annotation based mapping.
  12. 12. Hibernate Introduction with Annotation Before Java 5, Hibernate has XML way of configuring things. However with introduction of Annotations, the world has changed a lot. Many frameworks has adopted annotations as an alternative to XML. Hibernate has also adopted annotation. The XML way is still supported but annotation is the predominant way of working now. We will do the same example as we did in Hibernate Introduction using annotation. Download the Hibernate Core and Hibernate Annotations from https://www.hibernate.org/6.html. Lets make a Java project and pull the following libraries. From Hibernate Core (<hibernate-distribution-*>/lib/required)antlr-2.7.6common-collections-3.1.jardom4j-1.6.1.jarhibernate3.jarjavassist-3.9.0.GA.jarjta-1.1.jarslf4j-api-1.5.8.jar<hibernate-distribution-*>/lib/ -Choose between cglib or javassist From Hibernate Annotation:lib/ejb3-persistence.jarlib/hibernate-commons-annotations.jarhibernate-annotations.jar Download slf4j from http://www.slf4j.org/slf4j-simple-1.5.8.jar Hypersonic:hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar.For details see ((Hypersonic)).
  13. 13. Now lets write our domain class which is Student class.Student//Entity annotation represents that it is an entity class and is//mapped to a table in database. Table annotation tells about the//table name to which this entity is mapped@Entity@Table(name="Student")public class Student {//Id will correspond the primary key in the databaseprivate Long id;protected String name;//Id - Represents that it is a primary key column//GeneratedValue - How the key to be generated//column - Column to which this property is mapped@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name="STUDENT_ID")public Long getId() {return id;}public void setId(Long id) {this.id = id;}//There is annotation here so by default it is mapped to//the column with name NAME. In annotation, the properties are//by default mapped. In XML mapping by default the columns//are not mapped.public String getName() {return name;}
  14. 14. public void setName(String name) {this.name = name;}}If you have done the Hibernate Introduction, you will realize that the mapping has been pulled in theclass file itself in terms of annotations. The parallel can easily be drawn. Also now we do not need anymapping hbm.xml file. We still need the configuration XML, though the mapping will be done byreferencing to classhibernate.cfg.xml (Put it in the class path)<?xml version=1.0 encoding=utf-8?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- Database connection settings --><property name="connection.driver_class">org.hsqldb.jdbcDriver</property><property name="connection.url">jdbc:hsqldb:hsql://localhost</property><property name="connection.username">sa</property><property name="connection.password"></property><!-- JDBC connection pool (use the built-in) --><property name="connection.pool_size">1</property><!-- SQL dialect - This tells the SQL grammer to be used --><property name="dialect">org.hibernate.dialect.HSQLDialect</property><!-- Enable Hibernates automatic session context management --><property name="current_session_context_class">thread</property><!-- Disable the second-level cache --><property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
  15. 15. <!-- Log out all the sql that hibernate is issuing to datbase.This is very useful for debugging --><property name="show_sql">true</property><!-- validates the table structure as per mapping definition. --><property name="hbm2ddl.auto">validate</property><!-- Mapping class. --><mapping class="com.oyejava.Student"/></session-factory></hibernate-configuration>Lets write the Hibernate util class which is a utility class to make the Hibernate session factory. TheSession factory at runtime contains all the configuration and mapping details. From Session factory wecan get the Session, which is a lightweight object and helps us in interacting with the database.Session can be thought of as a Connection as in JDBC thought the Session may choose to not to openthe connection to the database.HibernateUtilpublic class HibernateUtil {private static SessionFactory sessionFactory;static{try{//By default it will look for hibernate.cfg.xml in the class pathsessionFactory=newAnnotationConfiguration().configure().buildSessionFactory();}catch(Throwable ex){throw new ExceptionInInitializerError(ex);}}public static SessionFactory getSessionFactory(){return sessionFactory;}
  16. 16. public static void shutdown(){//Close caches and connection poolgetSessionFactory().close();}}Now in the application logic, in this case in the main method we can create a Student object and saveit to the database.public class HibernateBasic {public static void main(String[] args) {//Get the session from the Session factorySession session = HibernateUtil.getSessionFactory().openSession();Transaction tx= session.beginTransaction();Student student = new Student();student.setName("oyeJava");Long studentId = (Long)session.save(student);System.out.println(studentId);tx.commit();session.close();}}Those who have done the hibernate in the XML way will notice that the only difference the two has gotis in terms of where the mapping is kept. You can download the source code from the attachmentsection down below.
  17. 17. Hibernate For Entity Beans of EJB Hibernate also support Entity beans and Java Persistence Provider(JPA) of EJB3.0+ specification. In fact many of the concepts of Entity beans has been taken from Hibernate. JBoss application server uses Hibernate as the default persistence provider for Entity beans and JPA. JPA has the notion of persistence unit which represents the configuration. EntityManagerFactory of JPA corresponds to SessionFactory and EntityManager corresponds to Session. Lets do the ((Hibernate Introduction with Annotation)) example of persisting Student object using Entity beans and JPA APIs Download the Hibernate Core, Hibernate Annotations and Hibernate EntityManager from https://www.hibernate.org/6.html . Lets make a Java project and pull the following libraries. From Hibernate Core (<hibernate-distribution-*>/lib/required)antlr-2.7.6commons-collections-3.1.jardom4j-1.6.1.jarhibernate3.jarjavassist-3.9.0.GA.jarjta-1.1.jarslf4j-api-1.5.8.jar<hibernate-distribution-*>/lib/ -Choose between cglib or javassist From Hibernate Annotation:lib/ejb3-persistence.jarlib/hibernate-commons-annotations.jarhibernate-annotations.jar From Hibernate Entity Manager:lib/jboss-archive-browsing.jarhibernate-entitymanager.jar
  18. 18. Download slf4j from http://www.slf4j.org/slf4j-simple-1.5.8.jar Hypersonic:hsqldb.jar - We will be using hypersonic database for this example. you need to download hypersonic jar.For details see ((Hypersonic)). Now lets write our domain class which is Student class.Note that it the same class as we did in ((Hibernate Introduction with Annotation)) Student //Entity annotation represents that it is an entity class and is //mapped to a table in database. Table annotation tells about the //table name to which this entity is mapped @Entity @Table(name="Student") public class Student { //Id will correspond the primary key in the database private Long id; protected String name; //Id - Represents that it is a primary key column //GeneratedValue - How the key to be generated //column - Column to which this property is mapped @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="STUDENT_ID") public Long getId() { return id; } public void setId(Long id) { this.id = id; }
  19. 19. //There is annotation here so by default it is mapped to//the column with name NAME. In annotation, the properties are//by default mapped. In XML mapping by default the columns//are not mapped.public String getName() {return name;}public void setName(String name) {this.name = name;}}Now lets write persistence.xml. This is the configuration file that EJB mandates. It is similar to whathibernate configuration file does. It can support multiple persistence provider other than hibernatealso.persistence.xml (Put in META-INF folder under source folder)<?xml version="1.0" encoding="UTF-8"?><persistence version="1.0"xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"><!-- This name is used to refer to this persistence context.This will be used while we make the EntityManagerFactory --><persistence-unit name="hibernateMapping"><!-- Persistence provider --><provider>org.hibernate.ejb.HibernatePersistence</provider><!-- Provide properites of persistence provider. This isspecific to each persistence provider. All hibernate related propertieswhich sit in hibernate.cfg.xml can be put here. --><properties><property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/><property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost"/>
  20. 20. <property name="hibernate.connection.username" value="sa"/><property name="hibernate.connection.password" value=""/></properties></persistence-unit></persistence>Now we just have to write our main class and start interacting with database.public class HibernateMappingJPA {public static void main(String[] args) {//The name hibernateMapping comes from persistence.xmlEntityManagerFactory emf =Persistence.createEntityManagerFactory("hibernateMapping");//EntityManager is similar to Session in hibernateEntityManager em = emf.createEntityManager();EntityTransaction tx = em.getTransaction();tx.begin();Student student = new Student();student.setName("James Bond");em.persist(student);//Query APIQuery query = em.createQuery("Select s from Student s where s.name like ?");query.setParameter(1, "James%");List<Student> studentList = query.getResultList();for(Student s :studentList){System.out.println(s.getName());}tx.commit();em.close();
  21. 21. }}Note that we do not have to map the entity class explicitly as these are scanned automatically basedon the @Entity annotation. The source code can be downloaded from the attachment section downbelow.Hibernate ConceptsEntity and Value TypeHibernate makes distinction between entity and value types. Entity types represent the objects thatcan be persisted to the database. They are the first class citizen in hibernate. Hibernate manages thelife cycle of and entity. An entity also has an identifier which identifies the different instances uniquely.Value types are objects which are managed in the context of an entity. They live and die within thescope of an entity. This distinction comes because of Hibernate philosophy of promoting rich domainmodel. This means more classes per table. Lets say we have Student Table which contains theAddress alsoStudent tableIDNAMECITYCOUNTRYNow we can map this table to two class. One Entity and another value typeStudent (entity class)@Entitypublic class Student{private Long id;private String name;private Address address;
  22. 22. //Setters and getters Address (value class) public class Address{ private String city; private String country; //setters and getters } So we have got two classes for one table. Also the life of Address object is within the life scope of Student object.The Student object can live independently but an independent address object has no meaning unless it is associated with a Student object. Flushing Flushing is the process of propagating the changes from the Java layer to the database. Whenever the call is done for a save, hibernate does not issues the SQL automatically. It keeps on noting the changes and queues all the SQL. The SQLs are issued to database at appropriate time. This propagation of changes is known as flushing. The default mode for flushing is automatic, where hibernate identifies when to flush. The flushing is done in the following cases:When the transaction is committed.Before query execution so that the query sees the latest data in the database.When session.flush() is called explicitly. The flushing mode can be changed by calling session.setFlushMode with parameter FlushMode.COMMIT. In this case the flushing happens onlyWhen the transaction is committed.When session.flush() is called explicitly. Dirty Checking Hibernate automatically tracks the changes in the entities when they are in managed state and persists the changes to the database. Look at the following example
  23. 23. //Get the session from the Session factory. In the first unit of work we persist the Student objectSession session = HibernateUtil.getSessionFactory().openSession();Transaction tx= session.beginTransaction();Student student = new Student();student.setName("oyeJava");Long studentId = (Long)session.save(student);tx.commit();session.close();//Start another unit of work. Note that we fetch the same row that we have saved.//Now change the name of student object but do not call any save or update method.//Still hibernate will figure out that the object has changed and hibernate will//persist the changes to the datbase.The process of finding the changes is known as dirty checkingalso.session = HibernateUtil.getSessionFactory().openSession();tx= session.beginTransaction();Student student1 = (Student)session.get(Student.class, studentId);student1.setName("Again Java");tx.commit();session.close();Whenever hibernate fetches or saves an object to the database, it keeps a snapshot of the object. Atthe point when hibernate goes to persist the changes, it loops through all the objects and matches itwith the snapshot it has got.If it identifies that the state of an entity has changed from its snapshot itflushes those changes to the database.Hibernate Debugging
  24. 24. Debugging Hibernate application tends to be tricky as there is a time lag between application issuing acalls on hibernate api and hibernate issuing SQL to the database.We will look into various strategies tolook into how to debug hibernate.ConfigurationEnable show_sql property in the hibernate configuration file. In your hibernate.cfg,xml put thefollowing<!-- Log out all the sql that hibernate is issuing to datbase.This is very useful for debugging --><property name="show_sql">true</property>This will flush all the sql that hibernate issues to databae. For example in ((Hibernate Introductionwith Annotation)) example you will see in the consoleHibernate: insert into Student (STUDENT_ID, name) values (null, ?)Enable format_sql to format the generate sql. However this will take more space. Change inhibernate.cfg.xml<!-- Format the logged sql --><property name="format_sql">true</property>In the consoleHibernate:insertintoStudent(STUDENT_ID, name)values(null, ?)To understand the origin of SQL, hibernate can put comments which can be enabled by putting thefollowing property in hibernate.cfg.xml
  25. 25. <!-- Show comment --> <property name="use_sql_comments">true</property> In the console Hibernate: /* insert com.oyejava.Student */ insert into Student (STUDENT_ID, name) values (null, ?) Enabling log4j Enabling logging level in log4j.properties can provide more information about the internal of application. Copy the sample log4j.properties from hibernate core download at etc folder. Run the application and you will tons of information about internals of hibernate. Tweak the level in log4j.properties. Enabling log4j.logger.org.hibernate.type at debug level will show the bind parameters. Do the following in log4j.properties. The following line is already there, you have to uncomment it. log4j.logger.org.hibernate.type=TRACE In the console Hibernate: insert into Student (STUDENT_ID, name) values (null, ?) 16:04:15,440 DEBUG StringType:133 - binding oyeJava to parameter: 1 Debugging Source The hibernate download comes with the source code. The src folder in the download has all the source. For hard to solve problems you can start digging into the source code itself. In eclipse you can do it as follows:Go to Project properties by right clicking on project name in navigator view and than click on Properties.Go to Java Build Path -> Source
  26. 26. Click on Link SourceIn the Linked Folder location and pick the location of hibernate source till srcIn the folder name give a name which does not conflicts with your present source location.Click on Finish and than Ok. You can now put break point in the application and can go the hibernatecode. Hibernate Tools Hibernate tool comes as an eclipse plugin. This has useful feature including HQL editor which helps in development. To install Hibernate Tool follow the steps :Check as per your eclipse version, the right version of tool at http://www.jboss.org/tools/download.html. You can either download or use the update mechanism. (Update mechanism is better if you are theonly one. If you want to share it among the team members go via download mechanism.) I will followthe download mechanism to show the steps.Extract the download zip file. There will be two folders features and plugins. Copy the files inside featuresinto eclipse/features. Similarly do for plugins.If eclipse is up, close it and restart.In eclipse click on Window->Open Perspective->Other.Click on hibernate. It will open the hibernate perspective. Hibernate Mapping Class The basic notion of ORM is mapping between class and table. A class is considered to be an entity when it gets the Entity annotation. Entity @Entity public class Student { We can provide a name to an entity. By default the name is the class name. We can give another name to entity so that conflicts do not occur because of same name entity sitting in different package @Entity(name="anotherStudent") public class Student {
  27. 27. By default this entity gets mapped to a table with same name. If we want to specify the table nameexplicitly@Entity@Table(name="Student")public class Student {Dynamic SQL GenerationHibernate by default generates the SQL for CRUD right in the beginning. This also means that even ifwe just update one property of the entity, still the update is issued for all the properties. If we wanthibernate to generate SQL at runtime only taking care of changed entity only than use Entityannotation coming from hibernate.Lets introduce a property in Student class age@Entity@Table(name="Student")public class Student {//Id will correspond the primary key in the databaseprivate Long id;protected String name;protected Integer age;//Getters and Setters...public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}...
  28. 28. Persist the student by making a new Student object and setting show_sql true.Student student = new Student();student.setName("oyeJava");Long studentId = (Long)session.save(student);The SQL generated by hibernate as seen in console isinsert into Student (STUDENT_ID, age, name) values (null, ?, ?)Note that though the age has not been set but still the SQL contains the age parameter. Now letsintroduce the Entity annotation from Hibernate so that we ask hibernate to generate the SQL atruntime rather than using the pre generated CRUD statement//dynamicInsert - Include only those properties which are not null in inserting the data//dynamicUpdate - Include only those properties which have changed@Entity@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)public class Student {The SQL generated at console isinsert into Student (name, STUDENT_ID) values (?, null)Note that the age field is absent. This is useful when the table has very large number of columns andmodification and insertion is done only on smaller number of columns.ImmutabilityWhen we know that an entity is not going to change at runtime. For example older messages fetchedfrom database, than we can ask hibernate to not to do dirty checking for it. This also results in betterperformance.@org.hibernate.annotations.Entity(dynamicInsert=true,
  29. 29. dynamicUpdate=true,mutable=false)public class Student {Hibernate Mapping IdentityIdentity of an object is the property which is mapped to primary key of the row in the database. The idof the entity is mapped by @Id annotation@Entity@Table(name="Student")public class Student {//Id will correspond the primary key in the databaseprivate Long id;protected String name;...//Id - Represents that it is a primary key column//GeneratedValue - How the key to be generated//column - Column to which this property is mapped@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name="STUDENT_ID")public Long getId() {return id;}public void setId(Long id) {this.id = id;}...Hibernate supports many identifier generation strategy which supports all the major databases
  30. 30. Hibernate does not allows to change the Id once it has been set. It throws an exception if an attemptis madestudent = new Student();Long studentId = (Long)session.save(student);//student.setId(80L); - This will throw an exceptionRight now JPA supports limited identifier generation strategy. So if the hibernate generation strategiesneed to be employed than do as follows:@Entity@org.hibernate.annotations.GenericGenerator(name="hibernate-native",strategy="native")public class Student{private Long id;protected String name;@Id@GeneratedValue(generator="hibernate-native")@Column(name="STUDENT_ID")public Long getId() {return id;}Its possible to write ones own identifier generation strategy by implementing IdentifierGeneratorinterface. However try to use one of the existing generator as Hibernate already has very richidentifier generators.Hibernate Mapping PropertiesIn this section we will look into how to map the different types of properties. All properties if mappedwith annotation are by default persistent. This is different from when XML is used for mapping. In XMLmapping, only the properties explicitly mapped are persistent.
  31. 31. Transient If a property needs to be stopped from being persistent. @Transient public int getActive() { return active; } Now this property does not becomes part of persistent mechanism. The property resides only in the Java layer. Temporal Allow to map java.util.Date and java.util.Calender. In SQL the date are differentiated by whether its a date, time or a timestamp. Timestamp has both date and time. However in Java the date is always a timestamp. It has all the information. So we have to deal with this mismatch also. //Options for TemporalType // - DATE // - TIME // - TIMESTAMP @Temporal(TemporalType.TIMESTAMP) public Date getBirthDate() { return birthDate; } Large Data Large data is characterized by whether it is a binary large data (BLOB) or character larger date (CLOB)Blob - byte[], Byte[]Clob - char[], Character[] BLOB and CLOB both are mapped with Lob annotation @Lob public byte[] getPicture() {
  32. 32. return picture;}EnumerationEnumeration are type safe way of restricting the choice in Java. Lets say we have enum defined inJava aspublic enum StudentType {CURRENT,ALUMNI}to specify the usage of this enum in entity@Enumerated(EnumType.STRING)public StudentType getStudentType() {return studentType;}Enum Type can be String or Ordinal. If String is specified, in the database CURRENT or ALUMNI isstored. If ordinal is specified 0 or 1 is saved. If Enum Type is omitted ORDINAL is taken as default.Derived PropertiesDerived properties are useful to calculate formulas or derived values which is not stored in databasebut important for business purpose.@org.hibernate.annotations.Formula("(MARKS/TOTAL_MARKS)*100")public Long getPercentage() {return percentage}The value is evaluated while fetching the entity so it might be outdated at other times. Its theresponsibility of the developer to keep it updated.The property appears in the SELECT statement onlyand does not participates in INSERT or UPDATE statement.Even SQL expression can be passed to the
  33. 33. underlying database so there is a chance to build database dependency.SQL functions including SQLsubselects can be used.Handling Generated ValuesIn DDL we define defaults to many values like SYSDATE for timestamp which means if we do not givevalue from Java it is automatically generated.After saving if we want to refresh the object in Javalayer, we will have to call a refresh on the object. The other way is that we can tell Hibernate torefresh the value automatically after an insertion. Make sure that you have dynamicInsert set to falseotherwise null value will be inserted into the database.@Column(updatable= false, insertable = false)@org.hibernate.annotations.Generated(org.hibernate.annotations.GenerationTime.INSERT)public Double getPendingAmount() {return pendingAmount;}Embedded classesEmbedded classes are useful for bringing fine domain modeling. We have one table but more classesmapped to it to bring rich domain model. Though Student table contains all the details for Student andhis address, we will map it to two classes.Student TableStudent_IdNameCityCountryLets have city and country mapped to a different class Address. We put Embeddable annotation on itto tell that it will be used as an embedded property in an entity class@Embeddablepublic class Address {protected String city;
  34. 34. protected String country;@Column(name = "ADD_CITY")public String getCity() {In the Student classprivate Address address;@Embeddedpublic Address getAddress() {return address;}//Setter methodBy default this will mapped to ADD_CITY column name as mapped in Address. To get it mapped toCITY column as in Student table, we ill have to override the column name.@Embedded@AttributeOverride (name= "city",column = @Column(name="CITY"))public Address getAddress() {return address;}Now in this case we can navigate to Address object by holding a reference of Student object. But itsnot possible to navigate from Address object to Student object. To build the bi directional navigation inAddress entityIn Address class@org.hibernate.annotations.Parentpublic Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}
  35. 35. Hibernate Collection Mapping Hibernate supports collection mapping as value type. In Hibernate collection mapping, the collection are mapped into a separate table but are not exposed as entity on the Java side. Hibernate supports following collection interfaces as value type:java.util.Set – java.util.HashSet is used to store value.java.util.SortedSet – java.util.TreeSet is used to store value.java.util.List – java.util.ArrayList is used to store value. Preserves the position with an index columnBag semantics – java.util.ArrayList is used to store valre however the position is not preserved.java.util.Map – java.util.HashMap is used to store value.java.util.SortedMap – java.util.TreeMap is used to store value. Let‟s say we want to store Phones for a Student. There are more than one Phone for a Student. So we will have two tables corresponding to Student and Phone. However we do not want to expose Phone Table STUDENT STUDENT_ID ... Table PHONE STUDENT_ID NUMBER ... STUDENT_ID is the foreign key and PHONE table has no primary key. To map the Phone collection as a Set in the Student Entity class Student class ... @org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class) @JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID")) @Column(name="PHONE_NO")
  36. 36. public Set<String> getPhones() {...The lifecycle of Phone is tightly coupled to Student. Also Phone table is not exposed as an entity. If theSet need to be sorted...@org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class)@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))@Column(name="PHONE_NO")@org.hibernate.annotations.Sort(type=org.hibernate.annotations.SortType.NATURAL)public Set<String> getPhones() {...A comparator can also be used for Sort type.To map the Phone collection as a list...@org.hibernate.annotations.CollectionOfElements@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))@org.hibernate.annotations.IndexColumn(name=“INDEX_POSITION", base =1)@Column(name="PHONE_NO")public List<String> getPhones() {return phones;}---Here the index is mapped to a INDEX_POSITION column in the table and preserves the ordering. Ifthe index is not given, this works like a Bag. Bag is a list but does not preserves the position.To map Phone as a map where PHONE_NAME will act as key and PHONE_NO as value from the PHONEtable. To map it...@org.hibernate.annotations.CollectionOfElements@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))
  37. 37. @org.hibernate.annotations.MapKey(columns = @Column(name="PHONE_NAME"))@Column(name="PHONE_NO")public Map<String,String> getPhones() {...Here the Phone table is mapped directly as a collection. We can also expose Phone as a value object.In this case define Phone as a class@Embeddablepublic class PhoneValue {protected Student student;protected String name;protected String phoneNumber;@org.hibernate.annotations.Parentpublic Student getStudent() {return student;}...Also in the above case we maintain a back pointer for Student so that we can navigate from Phone toStudent. To define the collection of embedded object in Student class...protected Collection<PhoneValue> phoneValues = new ArrayList<PhoneValue>();@org.hibernate.annotations.CollectionOfElements@JoinTable(name = "Student_Phone_Value",joinColumns = @JoinColumn(name="STUDENT_ID"))@CollectionId(columns= @Column(name="STUDENT_PHONE_VALUE_ID"),type=@org.hibernate.annotations.Type(type="long"),generator="sequence")public Collection<PhoneValue> getPhoneValues() {return phoneValues;}...
  38. 38. Hibernate collection mapping is a way of mapping the collection table as values. The lifecycle of the the collections are tightly bound to the collection of the owning entity. Hibernate Relationship Mapping Hibernate relationship mapping takes care of mapping the relationship in the relational world. The relationship that exist in the relational world are:@OneToOne@OneToMany@ManyToOne@ManyToMany Though the notion of directionality is not present in relational world, it is relevant for the Java world. So we will have to handle in the Java world whether we want to build unidirectional or bidirectional relation. Please note the the need of unidirectional or bidirectional relationship should be governed by your need of domain. For example if we have a Student and Address table with One to One relationship between them. One To One Lets say we have Address and Student in its own table and we expose Address also as an entity. @Entity public class AddressEntity implements Serializable{ protected Long id; …. @Id @GeneratedValue @Column(name="ADDRESS_ID") public Long getId() { return id; } Map the relationship in the Student entity with directionality build from Student side In Student class
  39. 39. ...private AddressEntity address;//Cascade Type defines that if the owning entity in this case Student is saved, than//whether the AddressEntity will also get saved.@OneToOne(cascade={CascadeType.ALL})@JoinColumn(name="ADDRESS_ID")public AddressEntity getAddressEntity() {return address;}...Also note the cascade type here. The cascade type defines whether the AddressEntity will get savedwhen we save Student. For example lets say the mapping in Student class, if we remove the Cascadetype will be:...private AddressEntity address;@OneToOne // comment out - (cascade={CascadeType.ALL})@JoinColumn(name="ADDRESS_ID")public AddressEntity getAddressEntity() {return address;}...Now lets try to save a Student and AddressEntityStudent student = new Student();AddressEntity add = new AddressEntity();student.setAddressEntity(add);//If you try to save student, it will throw an exception as//it finds AddressEntity wired to it but AddressEntity is transient.//To persist the transient AddressEntity with the Student uncomment the CascadeType//session.save(student);
  40. 40. We can make the primary key for both the related table same. It means that in the Address table theprimary key and foreign key are same.In the Student class@OneToOne(cascade={CascadeType.ALL})@PrimaryKeyJoinColumnpublic AddressEntity getAddressEntity() {return addressEntity;}In the above case the AddressEntity can be reached from Student but from AddressEntity you cannotreach to Student. Map the Student entity in the AddressEntity class...protected Student student;@OneToOne(mappedBy="bankAccount")public Student getStudent() { return student; }...Note that this relationship in the Java world does not makes any change to the relational world.In the case of bidirectional association, there is a notion of owning entity. The owning entity governsin what case the relationship will materialized in the database.The owning entity is the entity which ison the opposite or inverse side of mappedBy. In the case as the mappedBy is on the AddressEntity,the Student entity becomes the owning type. Now look at following piece of codeStudent student = new Student();AddressEntity add = new AddressEntity();//Map the relationship from AddressEntity sideadd.setStudent(student);//we will assume that CascadeType is All.session.save(student);
  41. 41. If we look into the database, the Student and AddressEntity both are created in the database but the relationship is not build between Student and AddressEntity table. To fix the problem change the above code to Student student = new Student(); AddressEntity add = new AddressEntity(); //Map the relationship from Student side student.setAddressEntity(add); //we will assume that CascadeType is All. session.save(student); Now the relationship will be properly created as we have made the relationship from owning side. Its a good price to build the relationship from both side whenever the relationship is effected from one side. Student student = new Student(); AddressEntity add = new AddressEntity(); //Good Practice: Map the relationship on both side student.setAddressEntity(add); add.setStudent(student); //we will assume that CascadeType is All. session.save(student); For owning entity, you have to take care of following:If a AddressEntity has to be assigned to a different student, than unset the addressEntity on the originalstudent and set it into the new student.For deleting a AddressEntity, unset it from the student object and than remove it from database callingremove method on entity manager. One To Many Lets have PhoneEntity table with one to Many relationship from Student.
  42. 42. Student TableSTUDENT_ID //Primary Key...PhoneEntity tablePHONE_ID //Primary KeySTUDENT_ID //Foreign Key...Now the PhoneEntity class looks like@Entitypublic class PhoneEntity implements Serializable{protected int id;protected String number;@Id@GeneratedValue@Column(name="PHONE_ID")public int getId() {There is no reference to Student in PhoneEntity class, though the relationship is maintained inPhoneEntity table in database. Now to build the One to Many relationship in Student@OneToMany(cascade={CascadeType.ALL})public Collection<PhoneEntity> getPhoneEntityList() {return phoneEntityList;}To save phone Entity the code would look likeCollection<PhoneEntity> phoneList = new ArrayList<PhoneEntity>();PhoneEntity p1 = new PhoneEntity();p1.setNumber("100");phoneList.add(p1);
  43. 43. PhoneEntity p2 = new PhoneEntity();p2.setNumber("200");phoneList.add(p2);student.setPhoneEntityList(phoneList);We can tell hibernate that if an element is removed from a collection than delete it from database asthis is the only reference to that entity.@OneToMany(cascade={CascadeType.ALL})@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)public Collection<PhoneEntity> getPhoneEntityList() {return phoneEntityList;}If we want the relationship data to be managed in a join table@OneToMany(cascade={CascadeType.ALL})@JoinTable(name="STUDENT_PHONE",joinColumns={@JoinColumn(name="STUDENT_ID")},inverseJoinColumns={@JoinColumn(name="PHONE_ID")})public Collection<PhoneEntity> getPhoneEntityList() {return phoneEntityList;}Now lets see Many To One unidirectional relationship. Lets say we have a country table and Studentis mapped to Country with Many to One relationship.Student TableSTUDENT_ID //Primary KeyCOUNTRY_ID //foreign Key...Country Table
  44. 44. COUNTRY_ID //Primary Key...Country Entity@Entitypublic class Country implements Serializable{protected long id;protected String name;@Id@GeneratedValue@Column(name="COUNTRY_ID")public long getId() {return id;}...Student Entityprivate Country country;@ManyToOne@JoinColumn(name="COUNTRY_ID")public Country getCountry() {return country;}Note that we are not using cascade here as normally the country is a master data and should not becreated or deleted in the context of a Student. To save a StudentCountry country = new Country();country.setName("India");session.save(country);student.setCountry(country);Many to one and One to many are two sides of the same relationship. Let‟s convert Student andCountry into bidirectional relationship.
  45. 45. //the owning side of relationship is Many To One@OneToMany(mappedBy="country")public Collection<Student> getStudentList() {return studentList;}For persistence to work we have to call student.setCountry. If we just callcountry.getStudentList().add(student), The relationship will not change in the database. As a goodpracticeAlways wire both side of relationship.Many To ManyManyToMany relationship happens when both side maintains collection based relationship.Let‟s takean example of Student and Language they speak. A student can speak many language. Similarly alanguage can be spoken by many studentsLanguage Entity bean@Entitypublic class Language implements Serializable{protected long id;protected String name;Student Bean@ManyToMany@JoinTable(name=“A_B",joinColumns={@JoinColumn(name=“C")},inverseJoinColumns={@JoinColumn(name=“D")})public Collection<Language> getLanguageList() {return languageList;}For Many to Many bidirectionalLanguage Bean
  46. 46. @ManyToMany(mappedBy="languageList") public Collection<Student> getStudentList() { return studentList; } For modifying the same ownership rule applies as we have seen in other bidirectional relationships. The collection can be fetched in certain order. E.g if we want to fetch the list of languages in certain order we can say on the Student side of relationship @ManyToMany @OrderBy(“name ASC”) @JoinTable(name="STUDENT_LANGUAGE", joinColumns={@JoinColumn(name="STUDENT_ID")}, inverseJoinColumns={@JoinColumn(name="LANGUAGE_ID")}) public List<Language> getLanguageList() { return languageList; } For descending order use name=DESC Hibernate Mapping Inheritance Inheritance is an important concept in Java but there is no counterpart in Relational world. There are some solutions is relational world but they are not widely used and also vendor specific. Hibernate provide some strategies to handle this situation where the inheritance hierarchy is mapped into the relational world. Lets have the java classes where we have a User class and Employee and Customer are inherited from it. The various strategies employed by hibernate to map this hierarchy to relational world is as follows:Single Table per class hierarchy – Single table has all properties of every class in the hierarchy.Table per concrete class – Each subclass has a table having all the properties of super class also.Table per subclass – Each class is mapped in its own table. There is separate table for super class andsubclass.Table Single Table per class hierarchy
  47. 47. In Single table per subclass, the union of all the properties from the inheritance hierarchy is mappedto one table. As all the data goes in one table, a discriminator is used to differentiate betweendifferent type of data.User (Base classe)//DiscriminatorColumn - Tells about the type of data//DiscriminatorValue - Is the data is representing User type, the value is "USER"@Entity@Inheritance(strategy=InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING)@DiscriminatorValue("USER")@Table(name="BASIC_USER")public class User{protected long id;protected String name;Customer class//There is no id column@Entity@DiscriminatorValue("CUST")public class Customer extends User{protected double creditLimit;Employee class//There is no id column@Entity@DiscriminatorValue("EMP")public class Employee extends User{protected String rank...}
  48. 48. The table structure would look like Basic_User Table ID NAME CREDIT_LIMIT RANK DISCRIMINATOR Now the objects can be saved polymorphically //User object referred by User type reference User user = new User(); user.setName("Superman"); session.save(user); Customer customer = new Customer(); customer.setName("Spiderman"); customer.setCreditLimit(1060); //User reference pointing to Customer object User user2 = customer; session.save(user2); Advantages of Single Table per class hierarchySimplest to implement.Only one table to deal with.Performance wise better than all strategies because no joins or sub-selects need to be performed. Disadvantages:Most of the column of table are nullable so the NOT NULL constraint cannot be applied.Tables are not normalized. Table per concrete class
  49. 49. In this case lets say our User class is abstract and Customer and Employee are concrete classes. So the table structure that comes out is basically one table for Customer and one table for Employee. The data for User is duplicated in both the tables. The User entity in this case is User @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class User{ protected long id; protected String name; @Id @GeneratedValue(strategy = GenerationType.AUTO) public long getId() { ... Customer class @Entity public class Customer extends User{ protected double creditLimit; ... This strategy is not popular and also have been made optional in Java Persistence API. Advantage:Possible to define NOT NULL constraints on the table. Disadvantage:Tables are not normalized.To support polymorphism either container has to do multiple trips to database or use SQL UNION kind offeature. Table per Sub class
  50. 50. In this case all the classes are mapped to its own table. Its highly normalized but performance is notgood.User class@Entity@Inheritance(strategy=InheritanceType.JOINED)@Table(name="BASIC_USER")public class User implements Serializable{protected long id;protected String name;...}Employee class@Entity@PrimaryKeyJoinColumn(name="EMPLOYEE_ID")public class Employee extends User{protected String rank;...}The derived class mapped table contain the foreign key which maps it to the base class. The tablestructure is as followsBasic_User TableIDNAMEEmployee tableEMPLOYEE_ID // Acts both as primary key and foreign key.RANK
  51. 51. Advantage:Tables are normalized.Able to define NOT NULL constraint. Disadvantage:Does not perform as well as SINGLE_TABLE strategy A comparison of three strategies is as follows: Table per Criteria Single Table Table per subclass concrete class One table for Data not normalized. each concrete Constraint for class. mandatory columns to Normalized. Not maintainable. be not nullable cannot Table Support Mandatory column constraint Change in base applied. can be applied class leads to Change in any subclass changes in all leads to change in tables of derived structure of Table class Discriminator Present Absent Absent Column Joins among table. For example simple SELECT. All data fetching Customer will require a is in one table. Using Retrieving join on Customer and User table. Separate Select or discriminator type, data If all user needs to be fetched Union Select individual types can be than it will put a join for all three selected tables Multiple. For User type one insert One insert or Updating and Single INSERT or on User table. For Customer type update for each Inserting UPDATE one insert on User table and subclass
  52. 52. another on Customer table. JPA Support Mandatory Optional Which Strategy to Choose Usually the choice is between Single Table and Table per subclass strategy. Table per concrete class is optional in JPA and may hinder your portability later on.They also represent the two ends of the spectrum. Some rule of thumbs are:If there are many properties common in the base class and very less uncommon properties in derivedclass. Go for Single table strategy. However make sure your database architect is comfortable withnullable constraint not put on the properties of derived class. If there are too many uncommonproperties, you might want to go for table per subclass strategy.Another criteria is the amount of polymorphic queries you do. If most of the time you fetch Customerand Employees separately you can go for Table per subclass as this will involve join only on two tables atime. However if you have requirements where you fetch User polymorphically most of the time, Singletable strategy will give better performance. Inheriting From a non entity base class Lets say we want to put Audit information in many tables. We can make Audit as a base class and make our entities class to inherit from Audit class Audit class @MappedSuperclass public class Audit { protected Date updateDate; protected Date createDate; @Temporal(TemporalType.TIMESTAMP) public Date getCreateDate() { return createDate; }
  53. 53. ...}User class@Entity@Table(name="BASIC_USER")//If we want to overried the column name than AttributeOverride is required@AttributeOverride(name="createDate",column=@Column(name="CREATE_DATE"))public class User extends Audit{...}Hibernate Persistent Context and SessionThe concept of Persistent Context and Session are central to the runtime behavior of Hibernate.Persistent Context is a run time memory area where Hibernate holds the references of objects andSession provides api to interact with the objects. Lets look them into one by one.Persistent ContextAt runtime whenever a session is opened and closed, between those open and close boundariesHibernate maintains the object in a Persistence Context. Think of it like a first level runtime cachewhich hibernate controls. Hibernate does automatic dirty checking and transactional write-behind forthe entity managed in Persistent Context. Hibernate guarantee a scope of Java object identity in thiscache. Only one object instance representing a particular database row exists in the cache. Hibernatecan extend the persistence context to span a whole conversation.Lets look at following piece of code. Here you can see the use of Session also.//Persistent Context 1 StartsSession session1 = HibernateUtil.getSessionFactory().openSession();Student studentA = (Student)session1.get(Student.class, studentId);Student studentB = (Student)session1.get(Student.class, studentId);if(studentA == studentB){System.out.println("Objects point to same refrence");}
  54. 54. session1.close(); //Persistent Context 1 Ends //Persistent Context 2 Starts Session session2 = HibernateUtil.getSessionFactory().openSession(); Student studentC = (Student)session2.get(Student.class, studentId); if(studentA == studentC){ System.out.println("Objects point to same refrence"); }else{ System.out.println("Objects do not point to same reference"); } session2.close(); //Persistent Context 2 Ends In the first case studentA and studentB will point to same object as Hibernate guarantees that against a same id only one object exist in the Persistent context. However in the second case studentA and studentC will be pointing to different objects as there is a different Persistent context. Hibernate does not maintains the guarantee beyond a Persistent Context Scope. Suppose after closing the session2, lets put all the objects in a set Set allStudents = new HashSet(); allStudents.add(studentA); allStudents.add(studentB); allStudents.add(studentC); The set will only have two objects. The good practice is to avoid using detached object in situation like above outside of a persistent context or objects coming from different persistent context. Also make sure that the hashCode() and equals() method are properly overridden. Important points about Persistent Context:Beware that hibernate keeps a snapshot of each persistent entity for dirty checking.Keep the size of your persistent context to minimum. Keep an eye to your sql logs. Avoid object graphs.Use session.evict(object) to clear big size objects once you are done with it. Use session.clear() whenyou want to remove all objects.
  55. 55. Use session.setReadOnly(object,true) you can disable dirty checking for a particular instance. The biggest problem that comes with ORM solutions are performance problems and memory issues Session Hibernate provides api through Session object to handle database interaction task. The database interaction task are as follows:Basic CRUD operationQuery ExecutionControl of TransactionManagement of Persistent Context To make an object persistent, save is used Student tempStudent = new Student(); tempStudent.setName("Om Shanti Om"); session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(tempStudent); tx.commit(); session.close(); To retrieve the object, we can use either load or get session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); //Either use get or load to fetch the entity student = (Student)session.get(Student.class, studentId); //student = (Student)session.load(Student.class, studentId); tx.commit(); session.close();
  56. 56. get() returns null if no database object for the id is found.load() throws ObjectNotFoundException.Also load method may return a proxy and tries to avoid hitting the database.session = HibernateUtil.getSessionFactory().openSession();tx = session.beginTransaction();Student loadStudent = (Student)session.load(Student.class, studentId);//The database hit happens hereloadStudent.getName();tx.commit();session.close();Hibernate automatically checks for the changes in the entity and flushes the changes to the database.session = HibernateUtil.getSessionFactory().openSession();Transaction tx = session.beginTransaction();student = (Student)session.get(Student.class, studentId);student.setName("Abhishek");//No explicit call is made to update the record in database. Still the changes//are flushed automaticallytx.commit();session.close();Data can be removed by calling delete onStudent loadStudent = (Student)session.load(Student.class, studentId);session.delete(student);An object has to be loaded in persistence context to use delete. The other option is to use bulkoperations which can issue direct deletes.Hibernate can also roll back the identifier of any entity thathas been deleted, it you enable the hibernate.use_identifier_rollback configuration option. The objectcan than be treated as transient object.
  57. 57. After persistence context is closed, item becomes a detached instance. The detached object can behandled using update or merge.If there is already an instance of object in the persistence context anexception is thrown.Managing Detached EntitiesDetached entities can be managed again by calling update.//update to student done outside of persistent scopestudent.setName("abc");session = HibernateUtil.getSessionFactory().openSession();Transaction tx = session.beginTransaction();//Reattaching. Hibernate will always issue an update,//even if the object is not dirty//The update can happens after attaching.session.update(student);student.setAddress(…);tx.commit();session.close();The detached entity can be attached using lock//Modification to a detached entitysession.setName("abc");session = HibernateUtil.getSessionFactory().openSession();Transaction tx = session.beginTransaction();//Reattaching. Lockmodes are NONE, READ, UPDATE.session.lock(student, LockMode.NONE);//It matters where changes are called. If changes are called before locking only,//the update is not issuedstudent.setAddress("Pune");
  58. 58. tx.commit();session.close();MergingMerging merges the detached instance with the managed instance.session.setName("oyejava");session = HibernateUtil.getSessionFactory().openSession();Transaction tx = session.beginTransaction();session.merge(student);tx.commit();session.close();Merging returns a new managed object. The detached instance remains detached. Merging includes allvalue typed properties and all additions and removals of elements to any collection. Usually it‟s betterto discard the detached instance and continue the work with the managed entity.Hibernate Entities Life cycleThe entities managed by Hibernate has a life cycle associated with them. Either you can make a newobject in heap and save it into database or the data can be fetched from the database and given touser as database. The hibernate objects go through certain stages in the life cycle. Only entity objectsparticipate in the life cycle. The value objects do not participate in the life cycle. The stages in the lifecycle of an entity managed by Hibernate are as follows:Transient ObjectsWhen objects are created in the Java layer with new or similar operator and they have nocorresponding record existing in database than these objects are termed as Transient objects. Theseobjects exist in heap. The primary key attribute of this object is still not set. Transient objects are nontransactional and in fact Hibernate has no knowledge of these objects at this point of time, Objectsthat are referenced only by other transient instances are, by default also transient. For an instance to
  59. 59. transition from transient to persistent state or to go managed state, it requires either a call to persistence manger or the creation of a reference from an already persistent instance. Persistent Objects Persistent entity is again an object in heap but it has a valid database identity associate with it. The entity goes into persistent object by one of following means:Objects instantiated by application and then made persistent by calling one of the methods on thepersistent manager.The objects become persistent when a reference is created from one of the persistent object.The entities retrieved from the database either by doing query, lookup or navigating the object graph. Persistent instances are always associated with a persistent context and Hibernate knows about them and may track them for dirty checking. Removed Object An object scheduled for deletion either by calling delete or because of orphan deletion of entities. One should not use the object in Java layer as the database record will be deleted at the end of session. A logic build around these objects might get into trouble. Detached Object The object in persistent state go into detached state after the persistent context is closed. Detached objects can be brought into other persistent context by reattachment or merging. Detached object still has a valid primary key attribute but it is no longer managed by Hibernate. Concept of owning entity in EJB and Hibernate The owning entity concept confuses many of the early adopters of Hibernate and JPA aka Entity beans in EJB3.0. We often confuse with the notion that we have to tell which of the entity is the owner.
  60. 60. Before we delve deeper into this question lets understand why this whole notion of ownership comesinto picture. The persistence provider gives us a lot of goodies in terms of saving us from handling lowlevel sql handling and coding in terms of rows and columns. Even we get into this lets move one morelevel above and understand that ORM framework provide us a way to think in terms of objects. Thethinking model with which Java programmers are comfortable with. OOAD is a very powerful notion asit helps us in thinking in terms of real world. ATM, Customer, Item, Bid, Auction become reusablenotions in software world. However to provide that notion to Software world, ORM does a lot of dirtywork (dirty checking !!!) for us.The most important feature that an ORM provides is transparent persistence. However to provide thatthe ORM framework does a lot of work under the hood. For example Hibernate keeps a copy of originalentity from the database and before flushing does a dirty checking (Ahh I have heard this before). Itwill compare the values with the working entity and in case of changes will generate the SQL.Now lets take a concrete example of User and Address both having one to one and bidirectionalrelationship. That means we have Address reference from User and User reference from Address. (Itdoes not matter whether we put the Fk on User side or Address side..Actually it matters with the kindof Sql the ORM tool will generate to materialize the relationship). Lets say for this example the foreignkey is on User side.Now as a good Java Programmer whenever we have to change the address of a user we will dofollowing:user.setAddress(add);add.setUser(add);If you are an EJB2.1 guy than please look into the EJB3.0. Its more work but with very simpleprogramming model and high portability.Now ORM frameworks will do the dirty checking and it will figure out that User and Address both haschanged so it will issue a call to update both address and user.For User it will beupdate user set address_id =?
  61. 61. and for address it will be similar call. So for almost all bidirectional relationship ORM framework willgenerate double update calls. This is a performance bottleneck Dr. Watson.So what we do. We as a programmer tell that which side is the owning, which means for therelationship to take into effect only one side of the dirty checking for the relationship needs to bedone. If we put inverse or mapped by on address than for the relationship to take effect we need to douser.setAddress(add);If we just do add.setUser(add) the change will not be propagated into the database. However as agood programmer we should wire both side of the relationship.Now lets think for a moment can ORM framework cannot handle this is some way.Think over it, it canbe done but will be a lot of bookkeeping and will complicate the frameworks a lot complex. Food forthought!!!Hibernate Query Language – HQLSession apis are used when an entity needs to be fetched from the database. To fetch list of recordswhich might involve joins we have to use Hibernate Query Language (HQL). HQL queries are similar toSQL. They are written in OO way. Hibernate supports criteria queries also which are type safe way ofwriting queries. Hibernate supports the JPA QL also. Hibernate also supports issuing native SQLqueries. The Query interface is used to build and execute queries.Fetching ListTo fetch a listIn HQL:Query hqlQuery = session.createQuery("Select s from Student s");List<Student> listStudent = hqlQuery.list();//Iterating the listfor(Student s: listStudent){System.out.println(s.getName());}
  62. 62. Using Criteria:Criteria crit = session.createCriteria(PhoneEntity.class);List<PhoneEntity> phones = crit.list();for(PhoneEntity p: phones){System.out.println(p.getNumber());}To restrict the list based on parameterHQL way:hqlQuery = session.createQuery ("from Student s where s.name like :name");//The wild card can use used as similar to SQLhqlQuery.setString("name", "ab%");List<Student> listStudent = hqlQuery.list();Using Criteria:Criteria crit = session.createCriteria(Student.class);crit.add(Restrictions.ilike(“name", “ab”);List<Student> students = crit.list();for(Student p: students ){System.out.println(p.getName());}PaginationPagination is used when there are huge number of records and we want to fetch a subset of it. Forexample we want to display the list of students on front end so we might just want to fetch the 25records which we want to display in third page. So we want the record which starts at 51th row andends at 75th rowHQL way:
  63. 63. Query hqlQuery =session.createQuery("from Student s order by s.name asc");hqlQuery.setFirstResult(51);hqlQuery.setMaxResults(25);List<Student> listStudent = hqlQuery.list();Criteria way:Criteria crit = session.createCriteria(PhoneEntity.class);crit.addOrder(Order.asc("number"));crit.setFirstResult(51);crit.setMaxResults(25);List<PhoneEntity> phones = crit.list();Binding ParametersIts always a good practice to bind the parameters rather than building the queries by Stringmanipulation. It will protect from SQL injection also. For example do not do likeSelect s from Student s where s.name like "James%".Rather than use parameter binding. The parameters can be bound either using named parameter orpositional parameter. Names parameter is better as it is more maintainable and readable.Named parameter binding:hqlQuery = session.createQuery("from Student s where s.name like :name");//The parameter is given a namehqlQuery.setString("name", "James%");List<Student> listStudent = hqlQuery.list();Positional parameter binding:hqlQuery = session.createQuery("from Student s where s.name like ?");
  64. 64. //The parameter is referred by position. For more than 1 parameter use number 0,1,2//as thesequence used in queryhqlQuery.setString0, "James%");listStudent = hqlQuery.list();Scrolling with database cursorHibernate provides support for JDBC feature called scrollable result where the cursor is held ondatabase. To open the curosrScrollableResults itemCursor = session.createQuery(“from Student s).scroll();The different functions to iterate using cursor//Go to first recorditemCursor.first();//Go to last recorditemCursor.last();//Go to next recorditemCursor.next();//Go to previous recorditemCursor.previous();Named QueryNamed query are queries where we give a name to it. These queries can bring performance as theycan be cached.@NamedQuery{name=“findAllStudents”,query=“SELECT s from Student s where s.firstName LIKE :firstName”)Calling the query:Query query = em.createNamedQuery(“findAllStudents”);
  65. 65. Polymorphic QueriesHibernate supports polymorphic query. For example suppose we have an inheritance structure on theOO side as mentioned in ((Hibernate Mapping Inheritance)).It does not matter whichever strategy youuse, Hibernate will ensure to fetch the record as per polymorphism.If the query is "Select u from User u", hibernate will fetch all the records form User, Customer andEmployee table.ExpressionsHibernate supports the expression which can narrow down results as per some criteria.Some example of expression are//amount between 1 and 10from Student s where s.pendingAmount between 1 and 10//amount > 100from Student s where s.pendingAmount > 100//Only those students whose email is as mentionedfrom Student s where s.email in („a@a.com‟,‟b@b.com‟)//students whose email are not setwhere s.email is null//students whose mails are setwhere s.email is not null//student refers to a phone collection and the collection is not emptyfrom Student i where i.phones is not emptyHibernate supports function also//lowering the name and than comparingfrom Student s where lower(s.name) like…
  66. 66. //Concatenating the name and than comparing as the database is having only one name field//which contains both first and last name togetherfrom Student s where concat(s.firstName,s.lastName) like..//Student has a collection of phone and has more than 2 phones.From Student s where size(s.phones) > 2//current_date will calculate the date and returnSelect upper(s.name), current_date() from Student sFetching Multiple ObjectsMultiple objects can be fetched as an object array.//It will return an Object [ ] with Student at index 0 and User at index 1Select s , u from Student s, User uScalar queries or ProjectionThis is very useful in reporting. Fetching a lot of objects when we are looking for only some columndata or want data from different tables leads to performance bottlenecks. In these cases its better touse scalar queries as it fetched only required dataSelect s.name , s.pendingAmount from Student sThis query will return an Object[].It‟s a scalar queries and the data fetched is not associated withpersistence context. The fetched data is not managed for dirty states.Query HintsThe flush mode can be disabled while executing the query. This can be useful when you do not wantHibernate to issue a flush before executing the query. For example if before executing the query youknow that the results of the query is not going to be affected by the dirty states of entities in thesession, for performance reason its better to disable the flush.//Query wayQuery q = session.createQuery(queryString).setFlushMode(FlushMode.COMMIT);
  67. 67. //Criteria wayCriteria c = session.createCriteria(Student.class).setFlushMode(FlushMode.COMMIT);//JPA wayQuery q = em.createQuery(queryString).setFlushMode(FlushModeType.COMMIT);The cache mode can also be disabled while executing query.It tells hibernate to not to put any entitiesin the second level cache//Query wayQuery q = session.createQuery(queryString).setCacheMode(CacheMode.COMMIT);//Critera wayCriteria c = session.createCriteria(Student.class).setCacheMode(CacheMode.COMMIT);//In JPA this is not supported as standard.If hibernate is the JPA provider than it can be used//using hibernate feature.Query q = em.createQuery(queryString).setHint(“org.hibernate.cacheMode”,org.hibernate.CacheMode.IGNORE);Dirty checking on the fetched objects can also be disabled. When you know that the fetched objectsare not going to change its better to disable the dirty checking. For example in case of fetching thelist of objects for display purpose only//Query wayQuery q = session.createQuery(queryString).setReadOnly(true);//Criteria wayCriteria c = session.createCriteria(Student.class).setReadOnly(true);//In JPA this is not supported as standard.//If hibernate is the JPA provider than it can be used using hibernate feature.Query q = em.createQuery(queryString).setHint(“org.hibernate.readOnly”, true);A timeout can also be passed as query hint which tells how long a long running query can be allowed
  68. 68. //Query wayQuery q = session.createQuery(queryString).setTimeout(60);//Criteria wayCriteria c = session.createCriteria(Student.class).setTimeout(60);//In JPA this is not supported as standard.//If hibernate is the JPA provider than it can be used using hibernate feature.Query q = em.createQuery(queryString).setHint(“org.hibernate.timeout”,60);Hibernate ShardsSharding is basically horizontal partitioning of data. If handled carefully, sharding can improveperformance. For example lets say for a online mail provider, the mail subscribers can run into hugenumbers. If all the rows of the database are sitting in the same server, it would hog a huge amount ofmemory. Sharding can help in horizontal partitioning of data. We can partition the records on thebasic of continents. The continent information derived from the country information. So the rowsbelonging to North America and Asia would be sitting on different servers. If the queries are alwayscontinent specific most of the time, this partitioning will help in improving the performance and alsoindexing will be better. The care should be taken that if we have queries which involve going todifferent databases to fetch the result set, and if this is a prevalent scenario, sharding would result indegradation of performance.Hibernate Shards helps in dealing with horizontal partitioning of data. To use shards, lets assume wehave a EmailUser table where the user data is saved. We will save the records alternately in twodifferent database and will see that how hibernate shields us from the knowledge that it is talking totwo different database. To make this tutorial, make a java project as outlined in HibernateIntroduction with Annotation. Also make sure Hypersonic jar is in the path. We will make a tutorialwhere the data is saved to two databases. The source code can be downloaded from the attachmentsection down below.Lets make the EmailUser class first. Note that it is a simple mapping class.@Entitypublic class EmailUser {
  69. 69. private BigInteger id; private String name; private String continent; //The id is generated by using a Shard specific generator @Id @GeneratedValue(generator="EmailIdGenerator") @GenericGenerator(name="EmailIdGenerator", strategy="org.hibernate.shards.id.ShardedUUIDGenerator") @Column(name="ID") public BigInteger getId() { return id; } public void setId(BigInteger id) { this.id = id; } //Getters and setters for other properties ...}As we are interacting with two different databases, we need to provide two configuration file toHibernate. If there are more than two databases, we have to provide same number of configurationfiles. Each file representing the details of a database. The first configuration file is usually the masterfile, where we provide all the details about other settings. Rest of the configuration files just containsthe details of connection to database and shard specific ids.hibernate0.cfg.xml (First configuration file)<?xml version=1.0 encoding=utf-8?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  70. 70. "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration> <!-- note the different name --> <session-factory name="HibernateSessionFactory0"> <!-- Database connection settings --> <propertyname="connection.driver_class">org.hsqldb.jdbcDriver</property> <propertyname="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Enable Hibernates automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Second-level cache --> <propertyname="cache.provider_class">org.hibernate.cache.EhCacheProvider/> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- property name="format_sql">true</property --> <!-- property name="use_sql_comments">true</property -->