Hibernate
Notes
&
Interview
HISTORY OF HIBERNATE
Hibernate was started in 2001 by Gavin King as an alternative to using EJB2-style Entity Beans. Its mission back then was to simply offer better persistence capabilities than offered by EJB2 by simplifying the complexities and allowing for missing features.
Early in 2003, the Hibernate development team began Hibernate2 releases which offered many significant improvements over the first release and would go on to catapult Hibernate as the "de facto" standard for persistence in Java.
The current version of Hibernate is Version 3.x. This version introduced new features like a new Interceptor/Callback architecture, user defined filters, and JDK 5.0 as of 2010 Hibernate 3 (version 3.5.0 and up) is a certified implementation of the Java Persistence API 2.0 specification via a wrapper for the Core module which provides conformity with the JSR.
HIBERNATE
--- Hibernate is a Persistence Framework is used to implement persistence logic or database operations.
Hibernate is the King among all the persistence Framework like JPA, IBatis, TopLink, JDO etc.
Architecture of Hibernate is Gavin King (from Redhat).
Hibernate is a ORM (Object Relational Mapping) Tool or Framework which simplifies the Persistence Operations.When we are implementing persistence logic with JDBC, we need to write the following code : try{
get the Connection(DataManager/DataSource);
create the required Statement (Statement, PreparedStatement, CallableStatement); prepared the SQL Statement
submit the query to database (executeXX()) process the result
}
catch(Exception e){
Handling the Exception }
finally{
cleanup }
@ In the case of JDBC, we are responsible for write the code for all the above said operations across the multiple programme.
@ Some JDBC statements are common like load the DataBase, Connection through DriverManager, catch the Exception and close the all Connection (1, 2, 3, 5, 7) are common across the multiple program which gives us the code duplication problem.
@ In the case of JDBC, we are responsible take the required resources and close the resources after using. If we are not closing the resources that may impact the application performance.
@ In the case of JDBC, we are responsible to write SQL statements, If SQL statements are not well-tuned that may also impact the application performance.
We write the Hibernate in two ways : ---Hibernate 3.1 – Core (XML Based)
Hibernate Features :
---1. Hibernate System responsible for taking the Connections, creating Statement and releasing the resources.
2. Hibernate support various Mapping Styles : i. Simple Mapping
ii. Collection Mapping iii. Inheritance Mapping
[a] Table per sub-class Mapping [b] Table per class Mapping
[c] Table per concrete class Mapping iv. Association Mapping
[a] One-to-One Mapping [b] One-to-Many Mapping [c] Many-to-Many Mapping v. Other Mapping.
3. Hibernate Supports two ways to manage Connection : [i] DriverManager Connection
[ii] DataSource Connection
4. Hibernate supports two ways to manage Transactions : [i] JDBC Transaction
[ii] JTA Transaction (EJB Container or Spring Container) 5. Hibernate provides various Primary Key generation algorithm. 6. Hibernate has in-built support for Batch Updates.
7. Hibernate provides various Caching mechanisms.
8. Hibernate provides various Object Oriented Query Language (OOQL) : [a] HQL (Hibernate Query Language)
[b] QBC (Query By Criteria) [c] QBE (Query By Example)
9. Hibernate System uses many Persistent best practices and forces the developer to use them for better performance.
Hibernate Architecture :
Fig : Hibernate Runtime System Configuration or AnnotationConfiguration :
--- There are Classes available in org.hibernate.cfg Package.
This is the first class that will be instantiated by the Hibernate application. We can use Configuration or AnnotationConfiguration class object for 2 tasks
:-(i) calling configure() method or configure(String) method. (ii) calling buildSessionFactory() method.
configure() method is responsible for following tasks :-(i) Reading the data from Hibernate Configuration object.
(ii) Reading the data from all the Hibernate mapping documents specified in the Configuration document.
buildSessionFactory() method is responsible for creating SessionFactory object. Configuration or AnnotationConfiguration object is Single Threaded and Short Lived.
Our Application Client Code Configuration SessionFactory Session Transaction Connection Provider Connection Transaction Factory JDBC API JNDI API JTA API DB Reposity JNDI Reposity
Once SessionFactory object is created then there is no use with Configuration or AnnotationConfiguration object.
SessionFactory :
---A SessionFactory is an interface available in org.hibernate package. SessionFactory object is Multi-Threaded and Long Lived. SessionFactory is clients for connection provider and Transaction Factory. The SessionFactory is created from a Configuration object, and as its name implies it is a factory for Session objects. The SessionFactory object is used by all the threads of an application. It is a thread safe object. The SessionFactory can also provide caching of persistent objects. The main use of session factory object is to get the session object for the application. SessionFactory hold an optional (second-level) cache of data that is reusable between transactions, at a process- or cluster-level. SessionFactorys are immutable. The behaviour of a SessionFactory is controlled by properties supplied at configuration time. These properties are defined on Environment.
A SessionFactory is usually only built once at startup. SessionFactory should be wrapped in some kind of singleton so that it can be easily accessed in an application code.
Creating object of SessionFactory :
SessionFactory sessionFactory = new Configuration().configure().buildSessionfactory();
When we call buildSessionFactory() method on Configuration object then following tasks will happen :
Set the defaults to many parameters like BatchSize, FetchSize etc. Generates and Caches the SQL Quires required.
Selects the Connection provider. Selects the Transaction Factory.
One SessionFactory object is created per database. Multiple SessionFactory objects (each requiring a separate Configuration) are created when connecting to multiple databases.
HibernateUtil.java Class for one Database
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil {
static SessionFactory factory = null; static{
Configuration cfg = new Configuration(); cfg = cfg.configure("hibernate.cfg.xml");
factory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory(){ return factory;
} }
HibernateUtil.java Class for two Databases
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil {
static SessionFactory orafactory = null; static SessionFactory jlcfactory = null; static{
Configuration cfg = new Configuration();
Configuration cfg1 = cfg.configure("oracle.cfg.xml");
orafactory = cfg1.buildSessionFactory();
Configuration cfg2 = cfg.configure("mysql.cfg.xml");
jlcfactory = cfg2.buildSessionFactory();
}
if(x==1){ return orafactory; }else{ return jlcfactory; } } } Session :
---This is an interface available in org.hibernate Package. The representation of single unit of work with the Java application and the persistence database is done by this object. The wrapping of a JDBC connection is the emphasized role of a Session interface object. This is the major interface between Java application and Hibernate. This is a runtime interface. The beginning and ending of a transaction cycle is bounded by the Session interface. The purpose of this interface is to perform create, read and delete operations for the objects that are mapped with entity classes.
Session session = sessionFactory.openSession(); Session Object is single Threaded and short Lived.
Session represents period of time where user can do multiple database operations.
Holds a mandatory (first-level) cache of persistent objects, used when navigating the object graph or looking up objects by identifier.
Session object
(i) use TransactionFactory to get the Transaction. (ii) get the Connection from Connection Provider.
It allows us to create query objects to retrieve persistent objects. Transaction :
---When Transaction is started, then following tasks will happened : Session Cache will be created.
Connection will be taken and will be associated with the current session. While Transaction is commit, following tasks will happen :
Session will be flushed.
Session Cache will be destroyed. Commit will be issued to database. Connection will be realised.
The general flow of Hibernate communication with RDBMS is :
--- The Hibernate configuration is to be loaded and creation of configuration object is done. The mapping of all hbm files will be performed automatically.
Creation of session factory from the configuration object. Obtain a session from the session factory.
Creation of HQL Query
Execution of the query in order to get the list of containing java objects. DAO + Hibernate (CURD Operation)
---DAO (Data Access Object) is J2EE Design Pattern. Problem :
We can store our Enterprise data in any repository like Flat File, XML Files, LDAP, RDBMS etc. Note - Commonly used Repository is RDBMS.
When we change the Persistence Storage or Persistence Technology or Framework then we have to change the Persistence Logic.
When We change the Persistence Logic then we may need to change the other Layers of the Application. This may give maintenance.
Context : When we are interacting with Persistence Storage. Solution :
Use DAO Design Pattern (J2EE Pattern) 1. Follow the Interface model.
2. Centralize the DAO instance creation in Factory DAO class.
3. DAO’s are stateless so create one and only instance for DAO using Singlton Pattern (GOF Pattern)
Hibernate Util
1. Making one SessionFactory for entire Application per DataBase.
2. Reading the data from Hibernate Configuration document and all the mapping document only once.
3. Reducing Code duplication. Hibernate Template
Reducing the code duplication.
Note : Hibernate uses XML document or properties file to define the object / relational mapping. The ORM File (.hbm file) contains the mapping between the Java object and corresponding database table.
Hibernate Mapping Type
---1. Simple Mapping : When our Persistence Class fields or variables or property of simple type like Primitives, Wrappers, String, Date etc. then use the Simple Mapping.
2. Collection Mapping : When our Persistence class fields or variables or property of Collection types like List, Set, Map, Array then use Collection Mapping.
3. Inheritance Mapping : When Multiple Persistence Classes are in Inheritance relationship then use Inheritance Mapping.
We can implement Inheritance Mapping in 3 ways :-[a] Table per sub-class Mapping
[b] Table per class Mapping
[c] Table per concrete class Mapping
4. Association Mapping : If we want to establish the relationship among different Persistence Classes, then we have use Association Mapping.
Depending on the Cardinality, there are 3 types of Association Mapping : [a] One-to-One Mapping
[b] One-to-Many Mapping [c] Many-to-Many Mapping
Depending on the Directionality, there are 2 types : 1. Uni-Directional Relationship Business Layer main() // Client Code Integration Layer Interface CustomerDAO{ addCustomer(); } class FactoryDAO{ HCD // Siglton class } DataBase J D B C Hibernate Runtime System class HibernateCustomer DAOImpl{ addCustomer(){ // Client Code } } --- Persistence Layer ---EIS Layer
2.
Bi- Directional Relationship@ Cardinality represents No. of objects participating in relationship on both the sides.
@ Directionality represents whether we can access the Data in one direction only or both the directions.
Inheritance Mapping :
---Hibernate supports the three basic inheritance mapping strategies: o table per class hierarchy
o table per subclass o table per concrete class
In addition, Hibernate supports a fourth, slightly different kind of polymorphism: o implicit polymorphism
It is possible to use different mapping strategies for different branches of the same inheritance hierarchy. You can then make use of implicit polymorphism to achieve polymorphism across the whole hierarchy. However, Hibernate does not support mixing <subclass>, <joined-subclass> and<union-<joined-subclass> mappings under the same root <class> element. It is possible to mix together the table per hierarchy and table per subclass strategies under the the same <class> element, by combining the<subclass> and <join> elements (see below for an example).
It is possible to define subclass, union-subclass, and joined-subclass mappings in separate mapping documents directly beneath hibernate-mapping. This allows you to extend a class hierarchy by adding a new mapping file. You must specify an extends attribute in the subclass mapping, naming a previously mapped superclass. Previously this feature made the ordering of the mapping documents important. Since Hibernate3, the ordering of mapping files is irrelevant when using the extends keyword. The ordering inside a single mapping file still needs to be defined as superclasses before subclasses.
<hibernate-mapping>
<subclass name="DomesticCat" extends="Cat" discriminator-value="D"> <property name="name" type="string"/>
</subclass>
</hibernate-mapping> Table per class hierarchy
Suppose we have an interface Payment with the implementors CreditCardPayment, CashPayment, andChequePayment. The table per hierarchy mapping would display in the following way:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT"> <property name="creditCardType" column="CCTYPE"/>
...
</subclass>
<subclass name="CashPayment" discriminator-value="CASH"> ...
</subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE"> ...
</subclass> </class>
Exactly one table is required. There is a limitation of this mapping strategy: columns declared by the subclasses, such as CCTYPE, cannot have NOT NULL constraints.
Table per subclass
A table per subclass mapping looks like this: <class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/>
</id>
<property name="amount" column="AMOUNT"/> ...
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/>
<property name="creditCardType" column="CCTYPE"/> ...
</joined-subclass>
<joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/>
...
</joined-subclass> </class>
Four tables are required. The three subclass tables have primary key associations to the superclass table so the relational model is actually a one-to-one association.
Table per subclass: using a discriminator
Hibernate's implementation of table per subclass does not require a discriminator column. Other object/relational mappers use a different implementation of table per subclass that requires a type discriminator column in the superclass table. The approach taken by Hibernate is much more difficult to implement, but arguably more correct from a relational point of view. If you want to use a discriminator column with the table per subclass strategy, you can combine the use of <subclass> and <join>, as follows:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="creditCardType" column="CCTYPE"/> ...
</join> </subclass>
<subclass name="CashPayment" discriminator-value="CASH"> <join table="CASH_PAYMENT">
<key column="PAYMENT_ID"/> ...
</join> </subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE"> <join table="CHEQUE_PAYMENT" fetch="select">
<key column="PAYMENT_ID"/> ...
</join> </subclass> </class>
The optional fetch="select" declaration tells Hibernate not to fetch the ChequePayment subclass data using an outer join when querying the superclass.
Mixing table per class hierarchy with table per subclass
You can even mix the table per hierarchy and table per subclass strategies using the following approach:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT">
<property name="creditCardType" column="CCTYPE"/> ...
</join> </subclass>
<subclass name="CashPayment" discriminator-value="CASH"> ...
</subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE"> ...
</subclass> </class>
For any of these mapping strategies, a polymorphic association to the root Payment class is mapped using <many-to-one>.
<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/> Table per concrete class
There are two ways we can map the table per concrete class strategy. First, you can use<union-subclass>.
<class name="Payment">
<id name="id" type="long" column="PAYMENT_ID"> <generator class="sequence"/>
</id>
<property name="amount" column="AMOUNT"/> ...
<union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/>
...
</union-subclass>
<union-subclass name="CashPayment" table="CASH_PAYMENT"> ...
</union-subclass>
<union-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> ...
</union-subclass> </class>
Three tables are involved for the subclasses. Each table defines columns for all properties of the class, including inherited properties.
The limitation of this approach is that if a property is mapped on the superclass, the column name must be the same on all subclass tables. The identity generator strategy is not allowed in union subclass inheritance. The primary key seed has to be shared across all unioned subclasses of a hierarchy.
If your superclass is abstract, map it with abstract="true". If it is not abstract, an additional table (it defaults to PAYMENT in the example above), is needed to hold instances of the superclass. Table per concrete class using implicit polymorphism
An alternative approach is to make use of implicit polymorphism: <class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/>
</id>
<property name="amount" column="CREDIT_AMOUNT"/> ...
</class>
<class name="CashPayment" table="CASH_PAYMENT"> <id name="id" type="long" column="CASH_PAYMENT_ID"> <generator class="native"/>
</id>
<property name="amount" column="CASH_AMOUNT"/> ...
</class>
<class name="ChequePayment" table="CHEQUE_PAYMENT"> <id name="id" type="long" column="CHEQUE_PAYMENT_ID"> <generator class="native"/>
</id>
<property name="amount" column="CHEQUE_AMOUNT"/> ...
</class>
Notice that the Payment interface is not mentioned explicitly. Also notice that properties
of Payment are mapped in each of the subclasses. If you want to avoid duplication, consider using XML entities (for example, [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] in
the DOCTYPE declaration and&allproperties; in the mapping).
The disadvantage of this approach is that Hibernate does not generate SQL UNIONs when performing polymorphic queries.
For this mapping strategy, a polymorphic association to Payment is usually mapped using <any>. <any name="payment" meta-type="string" id-type="long">
<meta-value value="CREDIT" class="CreditCardPayment"/> <meta-value value="CASH" class="CashPayment"/>
<meta-value value="CHEQUE" class="ChequePayment"/> <column name="PAYMENT_CLASS"/>
<column name="PAYMENT_ID"/> </any>
Mixing implicit polymorphism with other inheritance mappings
Since the subclasses are each mapped in their own <class> element, and since Payment is just an interface), each of the subclasses could easily be part of another inheritance hierarchy. You can still use polymorphic queries against the Payment interface.
<class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/>
</id>
<property name="amount" column="CREDIT_AMOUNT"/> ...
<subclass name="MasterCardPayment" discriminator-value="MDC"/> <subclass name="VisaPayment" discriminator-value="VISA"/>
</class>
<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN"> <id name="id" type="long" column="TXN_ID">
<generator class="native"/> </id>
...
<joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/>
<property name="amount" column="CASH_AMOUNT"/> ...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/>
<property name="amount" column="CHEQUE_AMOUNT"/> ...
</joined-subclass> </class>
Once again, Payment is not mentioned explicitly. If we execute a query against
the Payment interface, for example from Payment, Hibernate automatically returns instances of CreditCardPayment (and its subclasses, since they also
implement Payment), CashPayment and ChequePayment, but not instances ofNonelectronicTransaction.
Limitations
There are limitations to the "implicit polymorphism" approach to the table per concrete-class mapping strategy. There are somewhat less restrictive limitations to <union-subclass> mappings. The following table shows the limitations of table per concrete-class mappings, and of implicit polymorphism, in Hibernate.
Table : Features of inheritance mappings Inheritance strategy Polymorph ic many-to-one Polymorphic one-to-one Polymorphic one-to-many Polymorph ic
many-to-many Polymorphic load()/get() table per
class-hierarchy
<many-to-one> <one-to-one> <one-to-many> <many-to-many> s.get(Payment.class, id) table per
subclass <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.get(Payment.class, id) table per concrete-class (union-subclass) <many-to-one> <one-to-one> <one-to-many>(forinvers e="true"only)
<many-to-many> s.get(Payment.class, id) table per
concrete class (implicit polymorphism )
<any> not supported not supported <many-to-any>
s.createCriteria (Payment.class).add ( Restrictions.idEq(id) ). uniqueResult()
Association Mapping :
---# One-to-One Mapping through Core (Uni-Directional Mapping) Consider the following relationship between Student and Address entity. * One Student contains one Address.
* One Address belongs to one Student.
According to the relationship each student should have a unique address.
To create this relationship we need to have a STUDENT and ADDRESS table. The relational model is shown below.
To create the STUDENT and ADDRESS table we need to create the following hibernate mapping files. Student.hbm.xml is used to create the STUDENT table.
<?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Student"table="STUDENT" lazy=”false”> <idname="studentId"type="long"column="STUDENT_ID">
<generatorclass="native"/> </id>
<propertyname="studentName"type="string"column="STUDENT_NAME"/> <many-to-one name="studentAddress"
class="com.vaannila.student.Address"
column="STUDENT_ADDRESS"
not-null="true" cascade="all" unique="true" /> </class>
</hibernate-mapping>
We use the many-to-one element to create the one-to-one relationship between the Studentand Address entities. We do this my making the STUDENT_ADDRESS column unique in the STUDENT table.
Address.hbm.xml is used to create the ADDRESS table. <?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<idname="addressId"type="long"column="ADDRESS_ID"> <generatorclass="native"/>
</id>
<propertyname="street"column="ADDRESS_STREET"type="string"length="250"/> <propertyname="city"column="ADDRESS_CITY"type="string"length="50"/> <propertyname="state"column="ADDRESS_STATE"type="string"length="50"/> <propertyname="zipcode"column="ADDRESS_ZIPCODE"type="string"length="10"/> </class>
</hibernate-mapping>
Now create the hibernate configuration file and add all the mapping files. hibernate.cfg.xml
<?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>
<property name="hibernate.connection.driver_class"> org.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost/school</property> <property name="hibernate.connection.username">root</property>
<property name="connection.password">sandeep</property> <property name="connection.pool_size">1</property>
<property name="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <mapping resource="com/vaannila/student/Student.hbm.xml"/> <mapping resource="com/vaannila/student/Address.hbm.xml"/> </session-factory> </hibernate-configuration>
After creating the configuration file, generate java class files using Hibernate Tools. The following classes will be generated.
Student.java
packagecom.vaannila.student;
publicclassStudent implementsjava.io.Serializable { privatelongstudentId;
privateString studentName; private Address studentAddress; publicStudent() {}
publicStudent(String studentName, Address studentAddress) { this.studentName = studentName;
this.studentAddress = studentAddress; }
// Setters and Getters }
Address.java
packagecom.vaannila.student;
publicclassAddress implementsjava.io.Serializable { privatelongaddressId;
privateString city; privateString state; privateString zipcode; publicAddress() {}
publicAddress(String street, String city, String state, String zipcode) { this.street = street;
this.city = city; this.state = state; this.zipcode = zipcode; }
// Setter and Getter }
Create the Main class to run the example. Main.java packagecom.vaannila.student; importorg.hibernate.HibernateException; importorg.hibernate.Session; importorg.hibernate.Transaction; importcom.vaannila.util.HibernateUtil; publicclassMain {
publicstaticvoidmain(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null;
try{
transaction = session.beginTransaction();
Address address1 = newAddress("OMR Road", "Chennai", "TN","600097");
Address address2 = newAddress("Ring Road", "Banglore","Karnataka", "560000"); Student student1 = newStudent("Eswar", address1);
Student student2 = newStudent("Joe", address2); session.save(student1); session.save(student2); transaction.commit(); } catch(HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally{ session.close(); } } }
On executing the Main class we will see the following output. The Student table has two records.
Each student record points to a different address record, this illustrates the one-to-one mapping.
# One-to-Many Mapping through Core
---Consider the following relationship between Student and Phone entity.
According to the relationship a student can have any number of phone numbers.
To create this relationship we need to have a STUDENT, PHONE and STUDENT_PHONE table. The relational model is shown below.
To create the STUDENT and PHONE table we need to create the following hibernate mapping files. Student.hbm.xml is used to create the STUDENT and STUDENT_PHONE table.
<?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Student"table="STUDENT" lazy=”false”> <idname="studentId"type="long"column="STUDENT_ID">
<generatorclass="native"/> </id>
<propertyname="studentName"not-null="true"length="100"column="STUDENT_NAME"/> <set name="studentPhoneNumbers" table="STUDENT_PHONE" cascade="all">
<key column="STUDENT_ID" />
<many-to-many column="PHONE_ID" unique="true"class="com.vaannila.student.Phone" /> </set>
</class>
</hibernate-mapping>
we use many-to-many element to create the one-to-many relationship between the Student and Phone entities. Since a student can have any number of phone numbers we use a collection to hold the values. In this case we use Set. Many-to-many element is usually used to create many-to-many relationship, here we place the unique constraint on the PHONE_ID column, this makes the relationship one-to-many.
Phone.hbm.xml is used to create the PHONE table. <?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Phone"table="PHONE" lazy=”false”> <idname="phoneId"type="long"column="PHONE_ID">
<generatorclass="native"/> </id>
<propertyname="phoneType"length="10" column="PHONE_TYPE"/> <propertyname="phoneNumber"length="15" column="PHONE_NUMBER"/> </class>
</hibernate-mapping>
Now create the hibernate configuration file and add all the mapping files. hibernate.cfg.xml
Same as One-to-One Mapping
After creating the configuration file, generate java class files using Hibernate Tools. The following classes will be generated.
Student.java
packagecom.vaannila.student;
publicclassStudent implementsjava.io.Serializable { privatelongstudentId;
privateString studentName;
private Set<Phone> studentPhoneNumbers = new HashSet<Phone>(0); publicStudent() {}
publicStudent(String studentName) { this.studentName = studentName; }
publicStudent(String studentName, Set<Phone> studentPhoneNumbers) { this.studentName = studentName;
this.studentPhoneNumbers = studentPhoneNumbers; }
// Setter and Getter }
Phone.java
packagecom.vaannila.student;
publicclassPhone implementsjava.io.Serializable { privatelongphoneId;
privateString phoneType; privateString phoneNumber; publicPhone() {}
publicPhone(String phoneType, String phoneNumber) { this.phoneType = phoneType;
this.phoneNumber = phoneNumber; }
// Setter and Getter }
Create the Main class to run the example. Main.java
packagecom.vaannila.student; publicclassMain {
publicstaticvoidmain(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null;
try{
transaction = session.beginTransaction(); Set<Phone> phoneNumbers = new HashSet<Phone>(); phoneNumbers.add(new Phone("house","32354353")); phoneNumbers.add(new Phone("mobile","9889343423")); Student student = new Student("Eswar", phoneNumbers); session.save(student); transaction.commit(); } catch(HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally{ session.close(); } } }
On executing the Main class we will see the following output. The STUDENT table has one record.
The PHONE table has two records.
The STUDENT_PHONE table has two records to link the student and phone numbers.
A single student record points to two phone numbers, this illustrates the one-to-many mapping. # Many-to-one Mapping through Core
---Consider the following relationship between Student and Address entity.
According to the relationship many students can have the same address. To create this relationship we need to have a STUDENT and ADDRESS table. The relational model is shown below.
To create the STUDENT and ADDRESS table we need to create the following hibernate mapping files. Student.hbm.xml is used to create the STUDENT table.
<?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Student"table="STUDENT" lazy=”false”> <idname="studentId"type="long"column="STUDENT_ID">
<generatorclass="native"/> </id>
<propertyname="studentName"length="100"not-null="true"column="STUDENT_NAME"/> <many-to-one name="studentAddress"
class="com.vaannila.student.Address"
column="STUDENT_ADDRESS" cascade="all" not-null="true" /> </class>
</hibernate-mapping>
The many-to-one element is used to create the many-to-one relationship between the Studentand Address entities. The cascade option is used to cascade the required operations to the associated entity. If the cascade option is set to all then all the operations will be cascaded. For instance when you save a Student object, the associated Address object will also be saved automatically.
Address.hbm.xml is used to create the ADDRESS table. <?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Address"table="ADDRESS" lazy=”false”> <idname="addressId"type="long"column="ADDRESS_ID">
<generatorclass="native"/> </id>
<propertyname="street"column="ADDRESS_STREET"length="250"/> <propertyname="city"column="ADDRESS_CITY"length="50"/> <propertyname="state"column="ADDRESS_STATE"length="50"/> <propertyname="zipcode"column="ADDRESS_ZIPCODE"length="10"/> </class>
</hibernate-mapping>
Now create the hibernate configuration file and add all the mapping files. Hibernate.cfg.hml
Same as Previous
After creating the configuration file, generate java class files using Hibernate Tools. The following classes will be generated.
packagecom.vaannila.student;
publicclassStudent implementsjava.io.Serializable { privatelongstudentId;
privateString studentName; privateAddress studentAddress; publicStudent() {}
publicStudent(String studentName, Address studentAddress) { this.studentName = studentName;
this.studentAddress = studentAddress; }
// Setter and Getter }
Address.java
packagecom.vaannila.student;
publicclassAddress implementsjava.io.Serializable { privatelongaddressId;
privateString street; privateString city; privateString state; privateString zipcode; publicAddress() { }
publicAddress(String street, String city, String state, String zipcode) { this.street = street;
this.city = city; this.state = state; this.zipcode = zipcode; }
// Setter and Getter }
Create the Main class to run the example. Main.java
packagecom.vaannila.student; publicclassMain {
publicstaticvoidmain(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null;
try{
transaction = session.beginTransaction();
Address address = newAddress("OMR Road", "Chennai", "TN","600097");
// By using cascade=all option the address need not be saved explicitly when the student object is persisted the address will be automatically saved.
Student student1 = newStudent("Eswar", address); Student student2 = newStudent("Joe", address); session.save(student1); session.save(student2); transaction.commit(); } catch(HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally{ session.close(); } } }
On executing the Main class we will see the following output. The Student table has two records.
The Address table has one record.
Both the student records points to the same address record, this illustrates the many-to-one mapping.
# Many-to-Many Mapping through Core
---Consider the following relationship between Student and Course entity.
According to the relationship a student can enroll in any number of courses and the course can have any number of students.
To create this relationship we need to have a STUDENT, COURSE and STUDENT_COURSE table. The relational model is shown below.
To create the STUDENT and COURSE tables you need to create the following hibernate mapping files. Student.hbm.xml is used to create the STUDENT and STUDENT_COURSE table.
<?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Student"table="STUDENT" lazy=”false”> <idname="studentId"type="long"column="STUDENT_ID">
<generatorclass="native"/> </id>
<propertyname="studentName"length="100"not-null="true"column="STUDENT_NAME"/> <set name="courses" table="STUDENT_COURSE" cascade="all">
<key column="STUDENT_ID" />
<many-to-many column="COURSE_ID" class="com.vaannila.student.Course" /> </set>
</class>
</hibernate-mapping>
We use many-to-many element to create the many-to-many relationship between the Studentand Course entities. Since a student can enroll in any number of courses we use a collection to hold the values. In this case we use Set.
Course.hbm.xml is used to create the COURSE table. <?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<classname="com.vaannila.student.Course"table="COURSE" lazy=”false”> <idname="courseId"type="long"column="COURSE_ID">
<generatorclass="native"/> </id>
<propertyname="courseName"type="string"column="COURSE_NAME"/> </class>
</hibernate-mapping>
Now create the hibernate configuration file and add all the mapping files. Hibernate.cfg.hml
Same as Previous
After creating the configuration file, generate java class files using Hibernate Tools The following classes will be generated.
Student .java
packagecom.vaannila.student;
publicclassStudent implementsjava.io.Serializable { privatelongstudentId;
privateString studentName;
privateSet<Course> courses = newHashSet<Course>(0); publicStudent() {
}
publicStudent(String studentName) { this.studentName = studentName; }
publicStudent(String studentName, Set<Course> courses) { this.studentName = studentName;
this.courses = courses; }
// Setter and Getter }
Course .java
packagecom.vaannila.student;
publicclassCourse implementsjava.io.Serializable { privatelongcourseId;
privateString courseName; publicCourse() {
}
publicCourse(String courseName) { this.courseName = courseName; }
// Setter and Getter }
Create the Main class to run the example. Main.java
packagecom.vaannila.student; publicclassMain {
publicstaticvoidmain(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null;
try{
transaction = session.beginTransaction(); Set<Course> courses = newHashSet<Course>(); courses.add(newCourse("Maths"));
courses.add(newCourse("Computer Science")); Student student1 = newStudent("Eswar", courses); Student student2 = newStudent("Joe", courses); session.save(student1); session.save(student2); transaction.commit(); } catch(HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally{ session.close(); } } }
On executing the Main class you will see the following output. The STUDENT table has two records.
The STUDENT_COURSE table has four records to link the student and courses.
Each student has enrolled in the same two courses, this illustrates the many-to-many mapping.
# Hibernate Mapping Component through Core
---In this example we will learn how to map components using Hibernate. Consider the following relationship between Student and Address entity.
According to the relationship each student should have a unique address.
Since the Student and Address entities are strongly related (composition relation), it is better to store them in a single table. The relational model is shown below.
Student.hbm.xml is used to create the STUDENT table. <?xmlversion="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.vaannila.student.Student"table="STUDENT" lazy=”false”> <idname="studentId"type="long"column="STUDENT_ID">
<generatorclass="native"/> </id>
<propertyname="studentName"not-null="true" column="STUDENT_NAME"/> <componentname="studentAddress"class="com.vaannila.student.Address">
<propertyname="street"column="ADDRESS_STREET"
l
ength="250"/> <propertyname="city"column="ADDRESS_CITY"length="50"/> <propertyname="state"column="ADDRESS_STATE"length="50"/> <propertyname="zipcode"column="ADDRESS_ZIPCODE"length="10"/> </component></hibernate-mapping>
The component element is used to map all the Address entity fields to the STUDENT table. In Hibernate terms the Address entity is called the component and it cannot have its own primary key, it uses the primary key of the enclosing Student entity.
Now create the hibernate configuration file. hibernate.cfg.xml
<?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>
<property name="hibernate.connection.driver_class"> org.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost/school</property> <property name="hibernate.connection.username">root</property>
<property name="connection.password">sandeep</property> <property name="connection.pool_size">1</property>
<property name="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </property> <property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping resource="com/vaannila/student/Student.hbm.xml"/> </session-factory>
</hibernate-configuration>
After creating the configuration file, generate java class files using Hibernate Tools.
The following classes will be generated. We will still have a Student and Address class seperately but they will be mapped to only one table.
Student.java
packagecom.vaannila.student;
publicclassStudent implementsjava.io.Serializable { privatelongstudentId;
privateString studentName; privateAddress studentAddress; publicStudent() {
}
publicStudent(String studentName) { this.studentName = studentName; }
publicStudent(String studentName, Address studentAddress) { this.studentName = studentName;
this.studentAddress = studentAddress; }
// Setter and Getter }
Address.java
packagecom.vaannila.student;
publicclassAddress implementsjava.io.Serializable { privateString street;
privateString state; privateString zipcode; publicAddress() { }
publicAddress(String street, String city, String state, String zipcode) { this.street = street;
this.city = city; this.state = state; this.zipcode = zipcode; }
// Setter and Getter }
Create the Main class to run the example. Main.java
ackagecom.vaannila.student; publicclassMain {
publicstaticvoidmain(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null;
try{
transaction = session.beginTransaction();
Address address = newAddress("OMR Road", "Chennai", "TN","600097"); Student student = newStudent("Eswar", address);
session.save(student); transaction.commit(); } catch(HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally{ session.close(); } } }
On executing the Main class you will see the following output.
Working with Primary Key :
---Hibernate supports to Configure both the types of Primary Key : 1. Simple Primary Key
2. Composite Primary Key Simple Primary Key :
Hibernate Provides various Built-in Simple Primary Key Generators follows : increment
hilo (high low) sequence seqhilo
uuid (Universal User ID) guid identity native assigned select # using increment
<id name=”sid” column=”sid” type=”int”> <generator class=”increment”/>
</id> # using uuid
<id name=”sid” column=”sid”> <generator class=”uuid”/> </id>
# using sequence
<id name=”sid” column=”sid”> <generator class=”sequence”>
<param name=”sequence”>SID_SEQ</param> </generator>
</id> # using hilo
<id name=”cid” column=”cid” type=”int”> <generator class=”hilo”> <param name=”table”>hi_value</param> <param name=”column”>next_value</param> <param name=”max_10”>10</param> </generator> </id> # using seqhilo
<id name=”sid” column=”sid” type=”long”> <generator class=”seqhilo”>
<param name=”sequence”>SID_SEQ</param> <param name=”max_10”>100</param> </generator>
</id>
If these Built-In ID Generators are not suitable for our requirements then we can write our own Custom ID Generators.
Steps to write Custom ID Generators through Core:
---1. Write our own ID Generator by implementing the interface called IdentifierGenerator which is available in org.hibernate.id.IdentifierGenerator Package.
3. Write the required id generation logic in generate() method 4. <id column=”sid” name=”sid” type=”string”>
<generator class=”com.jlcindia.id.SidGenerator”/> </id>
Steps to write Custom ID Generators through Annotation: ---1. Create a custom class as follows :
public class SIDGenerator{
public static String getNextSid(){ // write code
} }
2. in Client side :
Student stu=new Student(SIDGenerator.getNextSid(), “Krishu”,”Patna”,8792461475); session.save(stu);
Composite Primary Key :
---Hibernate does not provides any Built-in ID Generators for Composite Primary Key, We have to write also Custom ID Generator.
Steps to configure Composite Primary Keys through Core
---1. Write one custom class which contains composite fields: public class SID{
private String bid; private String sid;
// Default Constructor & parameteraized Constructor // setters-getters method
}
2. Write one custom class which generate composite key: public class SIDGenerator{
public static SID getNextSid(String bid){ // write code
} }
3. in Student.java (Persistence class) public class Student{
private SID studebtId; ……….
}
4. in Student.hbm.xml File
<class name=”Student” table=”student”>
<composite-id name=”studentId” class=”SID”>
<key-property name=”bid” column=”bid” type=”string”/> <key-property name=”sid” column=”sid” type=”string”/> </composite-id>
……….. </class> 5. in Client class:
// insert record
SID id= SIDGenerator.getNextSid(“30”); // 30 is a bId, sId will auto generate. Student stu=new Student(id,”Krishu”,”Patna”,999999);
session.save(stu); // select record
Student stu=(Student)session.load(Student.class, new SID(“30”,”101”)); System.out.println(stu.getStudentId().getBid());
System.out.println(stu.getStudentId().getSid()); System.out.println(stu.getSname());
// 30 is bid, 101 is sid.
Steps to configure Composite Primary Keys through Annotation
---1. Write one custom class which contains composite fields and implements with Serializable: @Embeddable
public class SID implements Serializable{ private String bid;
private String sid;
// Default Constructor & parameteraized Constructor // setters-getters method
}
2. Write one custom class which generate composite key: public class SIDGenerator{
public static SID getNextSid(String bid){ // write code
} }
3. in Student.java (Persistence class) @Entity
@Table(name=”students”) public class Student{
@Id @Embedded @AttributeOverrides({ @AttributeOverride(name=”bid”,column=@Column(name=”bid”)), @AttributeOverride(name=”sid”,column=@Column(name=”sid”)) })
private SID studebtId; ……….
}
4. in Client class: // insert record
SID id= SIDGenerator.getNextSid(“30”); // 30 is a bId, sId will auto generate. Student stu=new Student(id,”Krishu”,”Patna”,999999);
session.save(stu); // select record
Student stu=(Student)session.load(Student.class, new SID(“30”,”101”)); System.out.println(stu.getStudentId().getBid());
System.out.println(stu.getStudentId().getSid()); System.out.println(stu.getSname());
// 30 is bid, 101 is sid. Types of Object States :
---Persistence Class Object can be found in three states : 1. Transient State
2. Persistent State 3. Detached State
Transient State : When Persistent Class object is newly created and not participated any session operations then that object is called as Transient Object. The state of that object is called Transient State. Transient Object does not Contain any Identify or Primary Key.
Persistent State : When Persistent Class object is participated any session operations then that object is called as persistent object. The State of that object is called Persistent State. Persistent Object contains any Identity or Primary Key.
Detached State : When Persistent class object is participated any session operations and removed from Session Cache then that object is called as Detached Object. The State of that object is called Detached State. Detached object contains any Identity or Primary Key.
Transaction Management :
---Transaction is the process of performing multiple database operations as one Unit with all-nothing criteria i.e. when all the database operations in the Unit are successful then Transaction is successful and should be committed. When any one database operation in the unit is failed then Transaction is failed and should be rolled back.
When we implement Transactions properly in our application, it guarantees ACID Properties. A - Atomicity
C - Consistency I - Isolation D – Durability
Atomicity : Definition of Transaction.
Consistency : When we are running the transaction we may enforce business rules as per the application requirement. Our application should be consistent when any business rule is failed. Otherwise we may get some inconsistent rules.
Consider the withdraw operation : 1. Minimum balance is 5 K 2. Only 5 withdraw per day. 3. if(ATM){ limit : 50 K } if(Branch){ limit : 5 L }
Isolation : We can run multiple transactions concurrently. These concurrently running multiple transactions should not disturb other transaction i.e. multiple transactions should run isolately. Case A
Consider the case where multiple transactions running concurrently and using multiple Account rows of Accounts Table.
Transaction A/c No.
Tx1 -> 101
Tx2 -> 102
Tx3 -> 103
Operations A/c No.
Withdraw from 101 Withdraw from 102 Withdraw from 103 Case B
Consider the case where multiple transaction running concurrently and using single account row of accounts table.
Account No. : 38746292 1. Transfer (withdraw)
2. bank teller (withdraw / deposit) 3. loan EMI (withdraw)
In Case B, we may get some problems which are called as Transaction Concurrency Problems. There are three Transaction Concurrency Problems :
1. Dirty Read Problem 2. Repeatable Read Problem 3. Phantom Read Problem
To Avoid these problems, we have to apply the one of the following required Transaction Isolation
Level :
1. READ_UNCOMMITTED
2. READ_COMMITTED
3. REPEATABLE_READ 4. SERIALIZABLE
Durability : Our enterprise data should be available for long time (as long as our enterprise is running). We have to protect our data from crashes, failures, so we have to implement proper backup and recovery mechanism and proper logging mechanism.
Dirty Read Problem : When Transaction reads the Dirty value (Modified but not Committed) then we may get some inconsistent results.
To avoid Dirty reads, we have to lock the column (Cell).
To lock the column, we have to apply Isolation Level called READ_COMMITTED.
Repeatable Read Problem : When a Transaction is reading the same row Repeatedly, we may get different kind of problem is called Repeatable Read Problem.
To avoid Repeatable Read Problem, we have to lock the row.
To Lock the Row, we have to apply Isolation Level called REPETABLE_READ.
Phantom Read Problem : When the Transaction is reading the set of Rows repeatedly, we may get different set of rows in different reads. This kind of problem is called Phantom Read Problem.
To avoid Phantom Reads, we have to lock the entire Table.
To lock the table, we have to apply Isolation Level called SERIALIZABLE. Types of Transactions :
1. Local Transactions 2. Distributed Transactions
Local Transactions : When the single Database is participating in the Transaction Operations then it is called as Local Transactions.
Distributed Transactions : When a two or more databases are participating in the Transaction Operations then it is called as Distributed Transactions
Types of Transactions : 1. Flat Transactions 2. Nested Transactions Example - Flat Transaction : begin tx1
op1 op2 op3 end tx2
Example - Nested Transaction : begin tx1 op1 op2 begin tx2 op3 op4 end tx2 op5 begin tx3
op6 op7 end tx3 op8 end tx1
Example Make a Trip : Mon-Fri (Bangalore -> Pune -> Delhi -> Mumbai -> Bangalore) JDBC Transaction Management
---1. Specify the Transaction Boundaries Connection con = null;
try{ con=……….; con.setAutoCommit(false); op1; op2; op3; con.commit(); } catch(Exception e){ if(con != null) con.rollback; } finally{ if(con != null) con.close(); }
2. Specify the Isolation Levels con.setTransactionIsolation(1/2/4/8);
Q. What will happen when we not specifying the Isolation Level ? Ans : Database Vendor specific Default Transaction Isolation Level will be used.
Q. How can we get Database Vendor specific Default Transaction Isolation Level ? Ans : int getDefaultTransactionIsolation() of Database MetaData.
Default Transaction Isolation Level : MySQL – 4, Oracle – 2 Hibernate Transaction Management
---1. Specifying the Transaction Boundaries Transaction tx = null; try{ tx = session.beginTransaction(); op1; op2; op3; tx.commit(); } catch(Exception e){ if(tx != null) con.rollback; }
2. Specifying the Isolation Levels
Write the following property in hibernate.cfg.xml
Q. Can we specify different Isolation Levels for Transaction running in Hibernate Application ?
Ans : No
Q. Can we specify different Isolation Levels for Transaction running in JDBC Application ?
Ans : Yes
Dirty
Read RepeatableRead PhantomRead Lock Type Concurrency
READ_UNCOMMITED No No No Not Lock R
e d u c e
READ_COMMITED Yes No No Column
REPEATABLE_READ Yes Yes No Row
SERIALIZABLE Yes Yes Yes Table
JDBC Hibernate JPA EJB2/EJB3 Spring
Local Tx. Yes Yes Yes Yes Yes
Distributed Tx. No No (Non-CME)Yes (CME) No (Non-CME)Yes (CME) Yes Yes
Flat Tx. Yes Yes Yes Yes Yes
Nested Tx. No No No No Yes
Query Language Supported by Hibernate : 1. HQL (Hibernate Query Language)
2. QBC (Query By Criteria) 3. QBE (Query BY Example) 4. Native SQL Queries 5. Named SQL Queries
Hibernate Query Language (HQL) :
Hibernate Query Language (HQL) is extremely powerful query language. HQL is much like SQL and are case-insensitive, except for the names of the Java Classes and properties. HQL is used to execute queries against database. Hibernate automatically generates the sql query and execute it against underlying database if HQL is used in the application. HQL is based on the relational object models and makes the SQL object oriented. HQL uses Classes and properties instead of tables and columns. HQL is extremely powerful and it supports Polymorphism, Associations, Much less verbose than SQL.
Why to use HQL?
Full support for relational operations: HQL allows representing SQL queries in the form of objects. Hibernate Query Language uses Classes and properties instead of tables and columns.
Return result as Object: The HQL queries return the query result(s) in the form of object(s), which is easy to use. This elemenates the need of creating the object and populate the data from result set.
Polymorphic Queries: HQL fully supports polymorphic queries. Polymorphic queries results the query results along with all the child objects if any.
Easy to Learn: Hibernate Queries are easy to learn and it can be easily implemented in the applications.
Support for Advance features: HQL contains many advance features such as pagination, fetch join with dynamic profiling, Inner/outer/full joins, Cartesian products. It also supports Projection, Aggregation (max, avg) and grouping, Ordering, Sub queries and SQL function calls.
Database independent: Queries written in HQL are database independent (If database supports the underlying feature).
Understanding HQL Syntax
Any Hibernate Query Language may consist of following elements: Clauses
Aggregate functions Subqueries
Clauses in the HQL are: from
select where order by group by
Aggregate functions are:
avg(...), sum(...), min(...), max(...) count(*)
count(...), count(distinct ...), count(all...) Subqueries
Subqueries are nothing but its a query within another query. Hibernate supports Subqueries if the underlying database supports it.
Hibernate Cache
---Cache is representation of Database near to Application. When we cache the Read mostly data, we can reduce the No. of round trips between our application server and database server which increases performance of our application.
In general, we can have 3 types of cache scopes : 1. Trancational Scope Cache
2. Process Scope Cache 3. Clustered Scope Cache.
Trancational Scope Cache : This kind of cache will created whenever the Transaction is started and Runs as long as Transaction is running. Transactional scope cache will be destroyed whenever the Transaction ends either by commit or by rollback.
Process Scope Cache : This kind of cache can be accessed by multiple Transactions running in the Application or process.
Clustered Scope Cache : When our enterprise application is large scale application then we must use cluster environment where multiple servers will be clustered and integrated with LBS (Load Balancing Server) for routing the requests. In the case of Clustered Scope Cache, when one node caches the data then same data will be replicated to other nodes automatically.
Fig. : Hibernate Cache Architecture First Level Cache :
* When we create a Transaction then we have to process more tasks like : Configuration
openSession create Transaction
call persistence class object process all tasks like updation.
* Multiple persistence object store in SessionCache. When tx.commit() method will be invoked then all transaction store in database and flushing all session object and closing transaction and all. * Tasks are :
1. Session cache is the first level cache.
2. Session cache is the Transactional Scope Cache.
3. Session cache is enabled by default and should not be disabled.
4. Whenever we insert or update or select or delete the records then those persistence objects will be placed automatically in session cache.
5. We can remove the persistence object from session cache using – evict(obj) & clear() Second Level Cache :
Query Cache is the second level cache.
Query Cache can be process scope or cluster scope cache.
Query Cache is disabled by default. You have to enable explicitly if required.
Whenever we execute the Hibernate queries (HQL, QBC etc. – select sql statement) then all the records returned by select statement will be placed in query cache.
Steps to implements Query Cache :
---1. Enable the query cache by writing the following property in hibernate configuration doc. <property name=”hibernate.cache.user_query_cache”>true</property>
2. Specify the Required cache provider in hibernate configuration doc.
<property name=”hibernate.cache.provider_class”>org.hibernate.cache.EhCacheProvider
</property>
Note : Cache provider supported by Hibernate : 1. HashTableCacheProvider
2. EhCacheProvider (for small application) 3. OSCacheProvider (not mostly use) 4. SWarmCacheProvider (not mostly use) 5. TreeCacheProvider (Jboss Cache Provider)
3. Specify the required caching concurrency strategies in Hibernate mapping doc. <cache usage=”xx”>
Usage value can be one of the following :
i> read-only ii> nonstrict-read-write iii> read-write iv> transactional Note : We have to specify the caching concurrency strategies for class, Collections and
Associations.
Example : class Student{ int cid;
String cname; Set emails; ---}
<class name=”Student” table=” Student”>
---<cache usage=”read-only”/> <property name=”cname”/>
<set name=”email” table=”emails”/> <cache usage=”read-only”/>
---</set>