Home  >  Article  >  Java  >  Detailed explanation of annotations and caching in Java's Hibernate framework

Detailed explanation of annotations and caching in Java's Hibernate framework

高洛峰
高洛峰Original
2017-01-23 11:53:301210browse

Annotations
Hibernate annotations are the latest way to define mappings without using XML files. You can use annotations in addition to or replacement of XML mapping metadata.

Hibernate annotations are a powerful way to provide mapping of metadata objects and relational tables. All the metadata is lumped together into the code of the POJO java file which helps the user to understand both the table structure and the POJO during the development process.

If you plan to port your application to other EJB3 specification ORM applications, you must use annotations to express mapping information, but still if you want greater flexibility, you should use XML-based mapping.

Environment settings Hibernate annotations
First of all, you must ensure that you are using JDK5.0, otherwise, you need to upgrade the JDK to JDK5.0 to take advantage of the native support of annotations.

Secondly, you need to install Hibernate's 3.x annotation distribution package, which can be obtained from SourceForge: (Download Hibernate Annotation) and copy hibernate-annotations.jar, lib/hibernate-comons-annotations.jar and lib/ejb3 -persistence.jar Assign the class instance from Hibernate annotation to CLASSPATH

annotation:
As mentioned, while using Hibernate annotation works all the metadata pestle into POJO java file along with the code above this can Help users understand the table structure and POJO at the same time during the development process.

Consider the objects 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 using annotations to map the objects of the Employee class 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 on a field and assumes that it should be accessed directly through the runtime domain as a property of an object. If you annotate the getId() method with @Id, access to the property will be allowed by default through getter and setter methods. Therefore, all other annotations are also placed on either field or getter method, following the selected strategy. The following section will explain the annotations used in the above class.

@Entity Note:
The EJB3 specifications are 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 that is finally visible in a protected scope.

@Table Annotation: The
@Table annotation allows the specified table to be used to save the details of this entity in the database.

The @Table annotation provides four properties that allow overriding the name of the table, its catalog, its schema, and enforcing unique constraints on columns within the table. Now, we are using the name of the EMPLOYEE table that was just given.

@Id and @GeneratedValue annotations:
Each entity bean will have a primary key annotated with the @Id annotation of the class. The primary key can be a single field or a combination of multiple fields depending on the table structure.

By default, the @Id annotation will automatically determine the most appropriate primary key generation strategy to use, but it can be applied by applying the @GeneratedValue annotation, which accepts two parameters, strategy and generator, which are not intended to be discussed here. Just use the default default key generation policy. Letting Hibernate determine the generator type to use makes code portable between different databases.

@Column Annotation: The
@Column annotation is used to specify the details of a column to which a field or attribute will be mapped. The following most commonly used attributes can be used with column annotations: The

name attribute allows the name of the column to be specified explicitly.

The length attribute allows the size of a column to be used to map a value, especially a string value.

nullable attribute allows the column to be marked NOT NULL when generating the schema.

The unique attribute allows columns to be marked as containing only unique values.

Create the application class:
Finally, we will create the main() method of the application class to run the application. We will use this application to save some employee records and then we will apply CRUD operations on the records.

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.listEmployees();
 
   /* 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.listEmployees();
  }
  /* 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 = 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)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)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 us create the 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:
Below are the steps to compile and run the above application. Please ensure that PATH and CLASSPATH are set appropriately before compilation and execution.

Remove the Employee.hbm.xml mapping file from the path.

Create the Employee.java source file as shown above, and compile it.

Create the ManageEmployee.java source file, as shown in the figure above, and compile it.

Execute the ManageEmployee binary file to run the program.

The following results will be obtained and recorded in the EMPLOYEE table.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
 
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
First Name: Zara Last Name: Ali Salary: 5000
First 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 sec
 
mysql>

Cache
Cache is all about application performance optimization and it resides in the application and between databases to avoid multiple database accesses, allowing performance-critical applications to perform better.

Caching is very important to Hibernate, which uses a multi-level caching scheme as described below:

Detailed explanation of annotations and caching in Javas Hibernate framework

第一级缓存:
第一级缓存是Session的缓存,是一个强制性的缓存,通过它所有的请求都必须通过。 Session对象不断自身的动力的对象,提交到数据库之前。

如果发出多个更新一个对象,Hibernate试图拖延尽可能长的时间做了更新,以减少发出的更新SQL语句的数量。如果您关闭会话,所有被缓存的对象都将丢失,要么持久,或在数据库中更新。

二级缓存:
二级缓存是可选的缓存和一级缓存,总是会征询任何试图找到一个对象的二级缓存之前。第二级缓存可以在每个类和每个集合基础上进行配置,主要负责在会话缓存的对象。

任何第三方缓存可以使用Hibernate。org.hibernate.cache.CacheProvider接口提供,必须实施提供Hibernate一个句柄缓存实现。

查询级别缓存:
Hibernate也实现了查询结果集缓存与二级缓存的紧密集成在一起。

这是一个可选功能,需要两个额外的物理缓存中保存缓存的查询结果和地区当一个表的最后更新的时间戳。这只是针对那些使用相同的参数经常运行的查询非常有用。

二级缓存:
Hibernate使用一级缓存,默认情况下,你什么都没有做使用第一级缓存。让我们直接进入可选的第二级缓存。并不是所有的类受益于缓存,这样一来就能禁用二级缓存是很重要的

Hibernate二级缓存被设置为两个步骤。首先,必须决定要使用的并发策略。在此之后,可以配置缓存过期和使用缓存提供物理缓存属性。

并发策略:
并发策略是一个中介的负责存储数据项在缓存并从缓存中检索它们。如果要启用二级缓存,将必须决定,为每个持久化类和集合,要使用的缓存并发策略。

Transactional: 使用这种策略的主要读取数据的地方,以防止过时的数据的并发事务,在更新的罕见情况下是至关重要的。

Read-write: 再次使用这种策略的主要读取数据的地方,以防止并发事务陈旧的数据是至关重要的,在更新的罕见情况。

Nonstrict-read-write: 这种策略不保证缓存与数据库之间的一致性。使用此策略,如果数据很少改变和陈旧数据的可能性很小关键是不关注。

Read-only: 并发策略适用于数据,永远不会改变。使用数据仅供参考。

如果我们要使用第二级缓存为我们的Employee类,让我们添加告诉Hibernate使用可读写的高速缓存策略Employee实例所需的映射元素。

<?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 class="native"/>
   </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>

 usage="read-write" 属性告诉Hibernate使用一个可读写的并发策略定义的缓存。

缓存提供者:
考虑到会用你的缓存候选类的并发策略后,下一步就是选择一个缓存提供程序。Hibernate迫使选择一个缓存提供整个应用程序。

Detailed explanation of annotations and caching in Javas Hibernate framework

在指定hibernate.cfg.xml配置文件中的缓存提供。选择EHCache作为第二级缓存提供程序:

<?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>

现在,需要指定缓存区域的属性。EHCache都有自己的配置文件ehcache.xml,在应用程序在CLASSPATH中。在ehcache.xml中Employee类高速缓存配置可能看起来像这样:

<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
 
<cache name="Employee"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>

就这样,现在启用Employee类的二级缓存和Hibernate现在二级缓存,每当浏览到一个雇员或当通过标识符加载雇员。

应该分析你所有的类,并选择适当的缓存策略为每个类。有时,二级缓存可能降级的应用程序的性能。所以建议到基准应用程序第一次没有启用缓存,非常适合缓存和检查性能。如果缓存不提高系统性能再有就是在使任何类型的缓存是没有意义的。

查询级别缓存:
使用查询缓存,必须先使用 hibernate.cache.use_query_cache="true"属性配置文件中激活它。如果将此属性设置为true,让Hibernate的在内存中创建所需的高速缓存来保存查询和标识符集。

接下来,使用查询缓存,可以使用Query类的setCacheable(Boolean)方法。例如:

Session session = SessionFactory.openSession();

Query query = session.createQuery("FROM EMPLOYEE");

query.setCacheable(true);

List users = query.list();

SessionFactory.closeSession();

Hibernate也支持通过一个缓存区域的概念非常细粒度的缓存支持。缓存区是这是给定一个名称缓存的一部分。

Session session = SessionFactory.openSession();

Query query = session.createQuery("FROM EMPLOYEE");

query.setCacheable(true);

query.setCacheRegion("employee");

List users = query.list();

SessionFactory.closeSession();

This code usage method tells Hibernate is used to store and lookup employee aspects of the query in the cache.

For more detailed articles on annotations and caching in Java's Hibernate framework, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn