annotation
Hibernate annotation is a latest method that does not use XML files to define mappings. Annotations can be used in XML mapping metadata that are separated or replaced.
Hibernate's annotations are a powerful way to provide mappings of metadata objects and relational tables. All metadata is pestled together with the POJO java file. This can help users understand the structure of the table and POJO during the development process.
If you intend to port the application to other EJB3-specific ORM applications, you must use annotations to represent the mapping information, but if you want greater flexibility, you should use XML-based mapping.
Setting Hibernate annotation in the environment First, you must make sure that you are using JDK5.0, otherwise, you need to upgrade JDK to JDK5.0 native support with annotations.
Secondly, you need to install Hibernate's 3.x annotation distribution package, you can use SourceForge: (Download Hibernate Annotation) and copy hibernate-annotations.jar, lib/hibernate-comons-annotations.jar and lib/ejb3-persistence.jar to assign from Hibernate annotations to CLASSPATH from Hibernate annotations.
Commented class instance:
As mentioned, all metadata that works with Hibernate annotation work into the POJO java file above this can help users understand both the table structure and the POJO during development.
Consider the object that will be stored using the following EMPLOYEE table:
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id));
The following is the mapping of the object Employee class with annotations to map with the defined EMPLOYEE table:
import javax.persistence.*;@Entity@Table(name = "EMPLOYEE")public class Employee { @Id @GeneratedValue @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "salary") private int salary; public Employee() {} public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this.firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this.lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this.salary = salary; }}Hibernate detects that the @Id annotation is against a field and assumes that it should access the properties of an object directly through the runtime domain. If @Id is annotated with getId() method, the property will be accessed by default via getter and setter methods. Therefore, all other comments are also placed in either field or getter method, as selected below the policy. The following section explains the comments used in the above class.
@Entity Annotation:
The EJB3 specification description is included in the javax.persistence package, so we import this package as the first step. Secondly, we used the @Entity annotation to mark this class as an entity bean Employee class, so it must have a parameterless constructor, which is finally visible with protection.
@Table Annotation:
The @Table annotation allows the specified table to be used to hold detailed information about the entity in the database.
The @Table annotation provides four properties that allow overriding the name of the table, its directory, its schema, and executing unique constraints on the columns in the table. Now, we are using the name of the EMPLOYEE table just now.
@Id and @GeneratedValue annotations:
Each entity bean will have a primary key annotated in the @Id annotation of the class. The primary key can be a single field or a combination of multiple fields according to the table structure.
By default, the @Id annotation automatically determines the most appropriate primary key generation strategy to use, but it can be used by applying the @GeneratedValue annotation, which accepts two parameters, strategy and generator, not to be discussed here, just use the default default key generation strategy. Let Hibernate determine the generator type to use to make the code portability between different databases.
@Column Annotation:
The @Column annotation is used to specify the details of the column to a field or property that will be mapped. The following most commonly used properties can be annotated using columns:
The name attribute allows explicitly specifying the name of the column.
The length property allows to map the size of a column that is especially for a string value.
The nullable property allows the column to be marked NOT when generating the schema.
The unique property allows columns marked as containing only unique values.
Create an application class:
Finally, we will create the main() method of the application class to run the application. We will use this app to save some employee records and then we will apply for records on CRUD operations.
import java.util.List; import java.util.Date;import java.util.Iterator; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction;import org.hibernate.cfg.AnnotationConfiguration;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new AnnotationConfiguration(). configure(). //addPackage("com.xyz") //add package if used. addAnnotatedClass(Employee.class). buildSessionFactory(); }catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Add few employee records in database */ Integer empID1 = ME.addEmployee("Zara", "Ali", 1000); Integer empID2 = ME.addEmployee("Daisy", "Das", 5000); Integer empID3 = ME.addEmployee("John", "Paul", 10000); /* List down all the employees */ ME.listEmployee(); /* Update employee's records */ ME.updateEmployee(empID1, 5000); /* Delete an employee from the database */ ME.deleteEmployee(empID2); /* List down new list of the employees */ ME.listEmployee(); } /* Method to CREATE an employee in the database */ public Integer addEmployee(String fname, String lname, int salary){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee employee = new Employee(); employee.setFirstName(fname); employee.setLastName(lname); employee.setSalary(salary); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } return employeeID; } /* Method to READ all the employees */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Employee").list(); for (Iterator iterator = employees.iterator(); iterator.hasNext();){ Employee employee = (Employee) iterator.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); } tx.commit(); } catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to UPDATE salary for an employee */ public void updateEmployee(Integer EmployeeID, int salary ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee employee = (Employee)session.get(Employee.class, EmployeeID); employee.setSalary( salary ); session.update(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to DELETE an employee from the records */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee employee = (Employee)session.get(Employee.class, EmployeeID); session.delete(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } }} Database configuration:
Now, let's create a hibernate.cfg.xml configuration file to define the relevant parameters of the database.
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <!-- Assume students is the database name --> <property name="hibernate.connection.url"> jdbc:mysql://localhost/test </property> <property name="hibernate.connection.username"> root </property> <property name="hibernate.connection.password"> cohondob </property></session-factory></hibernate-configuration>
Compile and execute:
Here are the steps to compile and run the above application. Make sure that PATH and CLASSPATH are set appropriately before compiling and executing.
Remove Employee.hbm.xml mapping file from the path.
Create the Employee.java source file as shown in the above image and compile it.
Create the ManageEmployee.java source file as shown in the above image and compile it.
Execute the ManageEmployee binary file to run the program.
The following results will be obtained and the records will be in the EMPLOYEE table.
$java ManageEmployee.........VARIOUS LOG MESSAGES WILL DISPLAY HERE.........First Name: Zara Last Name: Ali Salary: 1000First Name: Daisy Last Name: Das Salary: 5000First Name: John Last Name: Paul Salary: 10000First Name: Zara Last Name: Ali Salary: 5000First Name: John Last Name: Paul Salary: 10000
If you check the EMPLOYEE table, it should have the following records:
mysql> select * from EMPLOYEE;+----+------------+-----------+--------+| id | first_name | last_name | salary |+----+------------+-----------+--------+| 29 | Zara | Ali | 5000 || 31 | John | Paul | 10000 |+----+------------+-----------+--------+2 rows in set (0.00 secmysql>
cache
Caching is all about the performance optimization of the application and it is located between the application and the database to avoid multiple database accesses and allow performance-critical applications to perform better.
Caching is important for Hibernate, and it adopts a multi-level caching scheme described below:
Level 1 cache:
The first level cache is the Session cache, which is a mandatory cache, and all requests through it must be passed. Session objects are constantly being powered by objects before submitting them to the database.
If multiple updates are issued, Hibernate attempts to delay the updates for as long as possible to reduce the number of updates issued SQL statements. If you close the session, all cached objects will be lost, either persistent, or updated in the database.
Level 2 cache:
Level 2 cache is optional and Level 1 cache that will always be sought before any attempt to find an object's Level 2 cache. The second level cache can be configured on a per-class and per-category basis, mainly responsible for objects cached in session.
Any third-party cache can use Hibernate. The org.hibernate.cache.CacheProvider interface provides, and it is necessary to implement a handle cache implementation for providing Hibernate.
Query level cache:
Hibernate also implements the tight integration of query result set cache and level 2 cache.
This is an optional feature that requires two additional physical caches to save cached query results and regions when a table is last updated. This is just very useful for queries that often run with the same parameters.
Level 2 cache:
Hibernate uses Level 1 cache, by default, you do nothing with Level 1 cache. Let's go straight to the optional second level cache. Not all classes benefit from caching, so it is important to disable Level 2 cache.
Hibernate Level 2 cache is set to two steps. First, you must decide which concurrency strategy to use. After this, you can configure cache expiration and use cache to provide physical cache attributes.
Concurrency strategy:
A concurrency policy is a mediator responsible for storing data items in the cache and retrieving them from the cache. If you want to enable Level 2 caching, you will have to decide which cache concurrency policy to use for each persistent class and collection.
Transactional: Using this strategy to primarily read data to prevent concurrent transactions of outdated data is critical in rare cases of updates.
Read-write: Again using this strategy the main reading of data is critical to prevent concurrent transactions from stale data in rare cases of updates.
Nonstrict-read-write: This strategy does not guarantee consistency between cache and database. With this strategy, the key is not to pay attention if the data is rarely changed and the possibility of stale data is to be stale.
Read-only: The concurrency policy is suitable for data and will never change. The data used is for reference only.
If we want to use the second level cache as our Employee class, let's add the mapping elements required to tell Hibernate to use a readable and writeable cache policy for Employee instances.
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Employee" table="EMPLOYEE"> <meta attribute="class-description"> This class contains the employee detail. </meta> <cache usage="read-write"/> <id name="id" type="int" column="id"> <generator/> </id> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class></hibernate-mapping>
The usage="read-write" property tells Hibernate to use a cache defined by a read-write concurrency policy.
Cache Provider:
After considering the concurrency policy of your cache candidate class, the next step is to select a cache provider. Hibernate forces selecting a cache to serve the entire application.
Cache provided in the specified hibernate.cfg.xml configuration file. Select EHCache as the second level cache provider:
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <!-- Assume students is the database name --> <property name="hibernate.connection.url"> jdbc:mysql://localhost/test </property> <property name="hibernate.connection.username"> root </property> <property name="hibernate.connection.password"> root123 </property> <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> <!-- List of XML mapping files --> <mapping resource="Employee.hbm.xml"/></session-factory></hibernate-configuration>
Now, you need to specify the properties of the cache area. EHCache has its own configuration file ehcache.xml, in the application in CLASSPATH. In ehcache.xml, the Employee class cache configuration might look like this:
<diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="1000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120" overflowToDisk="true"/><cache name="Employee"maxElementsInMemory="500"eternal="true"timeToIdleSeconds="0"timeToLiveSeconds="0"overflowToDisk="false"/>
That's it, now enable the Employee class's secondary cache and Hibernate now have the secondary cache, whenever browsing to an employee or when the employee is loaded by an identifier.
You should analyze all your classes and select the appropriate caching strategy for each class. Sometimes, the secondary cache may degrade the performance of the application. So it is recommended to the benchmark application that does not enable caching for the first time, which is very suitable for caching and checking performance. If the cache does not improve system performance, it is meaningless to make any type of cache.
Query level cache:
Using query cache, it must be activated first in the hibernate.cache.use_query_cache="true" property configuration file. If this property is set to true, let Hibernate create the required cache in memory to save the query and identifier set.
Next, using query cache, you can use the setCacheable (Boolean) method of the Query class. For example:
Hibernate also supports very fine-grained cache support through the concept of a cache area. The cache is part of the cache given a name.
This code uses a method to tell Hibernate to store and find queries on employees in the cache.