詳解Java的Hibernate框架中的注解與緩存
注解
Hibernate注解是一個沒有使用XML文件來定義映射的最新方法??梢栽诔蛱鎿Q的XML映射元數(shù)據(jù)使用注解。
Hibernate的注解是強(qiáng)大的方式來提供元數(shù)據(jù)對象和關(guān)系表的映射。所有的元數(shù)據(jù)被杵到一起的代碼POJO java文件這可以幫助用戶在開發(fā)過程中同時要了解表的結(jié)構(gòu)和POJO。
如果打算讓應(yīng)用程序移植到其他EJB3規(guī)范的ORM應(yīng)用程序,必須使用注解來表示映射信息,但仍然如果想要更大的靈活性,那么應(yīng)該使用基于XML的映射去。
環(huán)境設(shè)置Hibernate注釋
首先,必須確保使用的是JDK5.0,否則,需要JDK升級到JDK5.0帶注解的原生支持的優(yōu)勢。
其次,需要安裝Hibernate的3.x注解分發(fā)包,可從SourceForge上: (Download Hibernate Annotation) 并拷貝 hibernate-annotations.jar, lib/hibernate-comons-annotations.jar 和 lib/ejb3-persistence.jar 從Hibernate注解分配到CLASSPATH
注釋的類實(shí)例:
正如提到的,同時使用Hibernate注釋工作的所有元數(shù)據(jù)杵成隨著代碼的POJO java文件上面這可以幫助用戶在開發(fā)過程中同時了解表結(jié)構(gòu)和POJO。
考慮到將要使用下面的EMPLOYEE表來存儲的對象:
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) );
下面是用注解來映射與定義的EMPLOYEE表的對象Employee類的映射:
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檢測@Id注釋是對一個字段,并假設(shè)它應(yīng)該直接通過在運(yùn)行時域訪問一個對象的屬性。如果將@Id注釋getId()方法,將通過getter和setter方法默認(rèn)情況下允許訪問屬性。因此,所有其他注釋也被放置在任一字段或getter方法,以下所選擇的策略。下面的部分將解釋在上面的類中使用的注釋。
@Entity 注解:
在EJB3規(guī)范說明都包含在javax.persistence包,所以我們導(dǎo)入這個包作為第一步。其次,我們使用了@Entity注解來這標(biāo)志著這個類作為一個實(shí)體bean Employee類,因此它必須有一個無參數(shù)的構(gòu)造函數(shù),總算是有保護(hù)的范圍可見。
@Table 注解:
@Table注釋允許指定的表將被用于保存該實(shí)體在數(shù)據(jù)庫中的詳細(xì)信息。
@Table注釋提供了四個屬性,允許覆蓋表的名稱,它的目錄,它的架構(gòu),并執(zhí)行對列的唯一約束在表中?,F(xiàn)在,我們使用的是剛剛是EMPLOYEE表的名稱。
@Id 和 @GeneratedValue 注解:
每個實(shí)體bean將有一個主鍵,注釋在類的@Id注解。主鍵可以是單個字段或根據(jù)表結(jié)構(gòu)的多個字段的組合。
默認(rèn)情況下,@Id注解會自動確定要使用的最合適的主鍵生成策略,但可以通過應(yīng)用@GeneratedValue注釋,它接受兩個參數(shù),strategy和generator,不打算在這里討論,只使用默認(rèn)的默認(rèn)鍵生成策略。讓Hibernate確定要使用的generator類型使不同數(shù)據(jù)庫之間代碼的可移植性。
@Column 注解:
@Column批注用于指定的列到一個字段或?qū)傩詫⒈挥成涞募?xì)節(jié)??梢允褂昧凶⑨屢韵伦畛S玫膶傩裕?/p>
name屬性允許將顯式指定列的名稱。
length 屬性允許用于映射一個value尤其是對一個字符串值的列的大小。
nullable 屬性允許該列被標(biāo)記為NOT NULL生成架構(gòu)時。
unique 屬性允許被標(biāo)記為只包含唯一值的列。
創(chuàng)建應(yīng)用程序類:
最后,我們將創(chuàng)建應(yīng)用程序類的main()方法來運(yùn)行應(yīng)用程序。我們將使用這個應(yīng)用程序,以節(jié)省一些員工的記錄,然后我們將申請CRUD操作上的記錄。
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();
}
}
}
數(shù)據(jù)庫配置:
現(xiàn)在,讓我們創(chuàng)建hibernate.cfg.xml配置文件來定義數(shù)據(jù)庫的相關(guān)參數(shù)。
<?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>
編譯和執(zhí)行:
下面是步驟來編譯并運(yùn)行上述應(yīng)用程序。請確保已在進(jìn)行的編譯和執(zhí)行之前,適當(dāng)?shù)卦O(shè)置PATH和CLASSPATH。
從路徑中刪除Employee.hbm.xml映射文件。
創(chuàng)建Employee.java源文件,如上圖所示,并編譯它。
創(chuàng)建ManageEmployee.java源文件,如上圖所示,并編譯它。
執(zhí)行ManageEmployee二進(jìn)制文件來運(yùn)行程序。
會得到以下結(jié)果,并記錄將在EMPLOYEE表中。
$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
如果檢查EMPLOYEE表,它應(yīng)該有以下記錄:
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>
緩存
緩存是所有關(guān)于應(yīng)用程序的性能優(yōu)化和它位于應(yīng)用程序和數(shù)據(jù)庫之間,以避免數(shù)據(jù)庫訪問多次,讓性能關(guān)鍵型應(yīng)用程序有更好的表現(xiàn)。
緩存對Hibernate很重要,它采用了多級緩存方案下文所述:

第一級緩存:
第一級緩存是Session的緩存,是一個強(qiáng)制性的緩存,通過它所有的請求都必須通過。 Session對象不斷自身的動力的對象,提交到數(shù)據(jù)庫之前。
如果發(fā)出多個更新一個對象,Hibernate試圖拖延盡可能長的時間做了更新,以減少發(fā)出的更新SQL語句的數(shù)量。如果您關(guān)閉會話,所有被緩存的對象都將丟失,要么持久,或在數(shù)據(jù)庫中更新。
二級緩存:
二級緩存是可選的緩存和一級緩存,總是會征詢?nèi)魏卧噲D找到一個對象的二級緩存之前。第二級緩存可以在每個類和每個集合基礎(chǔ)上進(jìn)行配置,主要負(fù)責(zé)在會話緩存的對象。
任何第三方緩存可以使用Hibernate。org.hibernate.cache.CacheProvider接口提供,必須實(shí)施提供Hibernate一個句柄緩存實(shí)現(xiàn)。
查詢級別緩存:
Hibernate也實(shí)現(xiàn)了查詢結(jié)果集緩存與二級緩存的緊密集成在一起。
這是一個可選功能,需要兩個額外的物理緩存中保存緩存的查詢結(jié)果和地區(qū)當(dāng)一個表的最后更新的時間戳。這只是針對那些使用相同的參數(shù)經(jīng)常運(yùn)行的查詢非常有用。
二級緩存:
Hibernate使用一級緩存,默認(rèn)情況下,你什么都沒有做使用第一級緩存。讓我們直接進(jìn)入可選的第二級緩存。并不是所有的類受益于緩存,這樣一來就能禁用二級緩存是很重要的
Hibernate二級緩存被設(shè)置為兩個步驟。首先,必須決定要使用的并發(fā)策略。在此之后,可以配置緩存過期和使用緩存提供物理緩存屬性。
并發(fā)策略:
并發(fā)策略是一個中介的負(fù)責(zé)存儲數(shù)據(jù)項在緩存并從緩存中檢索它們。如果要啟用二級緩存,將必須決定,為每個持久化類和集合,要使用的緩存并發(fā)策略。
Transactional: 使用這種策略的主要讀取數(shù)據(jù)的地方,以防止過時的數(shù)據(jù)的并發(fā)事務(wù),在更新的罕見情況下是至關(guān)重要的。
Read-write: 再次使用這種策略的主要讀取數(shù)據(jù)的地方,以防止并發(fā)事務(wù)陳舊的數(shù)據(jù)是至關(guān)重要的,在更新的罕見情況。
Nonstrict-read-write: 這種策略不保證緩存與數(shù)據(jù)庫之間的一致性。使用此策略,如果數(shù)據(jù)很少改變和陳舊數(shù)據(jù)的可能性很小關(guān)鍵是不關(guān)注。
Read-only: 并發(fā)策略適用于數(shù)據(jù),永遠(yuǎn)不會改變。使用數(shù)據(jù)僅供參考。
如果我們要使用第二級緩存為我們的Employee類,讓我們添加告訴Hibernate使用可讀寫的高速緩存策略Employee實(shí)例所需的映射元素。
<?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使用一個可讀寫的并發(fā)策略定義的緩存。
緩存提供者:
考慮到會用你的緩存候選類的并發(fā)策略后,下一步就是選擇一個緩存提供程序。Hibernate迫使選擇一個緩存提供整個應(yīng)用程序。

在指定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>
現(xiàn)在,需要指定緩存區(qū)域的屬性。EHCache都有自己的配置文件ehcache.xml,在應(yīng)用程序在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" />
就這樣,現(xiàn)在啟用Employee類的二級緩存和Hibernate現(xiàn)在二級緩存,每當(dāng)瀏覽到一個雇員或當(dāng)通過標(biāo)識符加載雇員。
應(yīng)該分析你所有的類,并選擇適當(dāng)?shù)木彺娌呗詾槊總€類。有時,二級緩存可能降級的應(yīng)用程序的性能。所以建議到基準(zhǔn)應(yīng)用程序第一次沒有啟用緩存,非常適合緩存和檢查性能。如果緩存不提高系統(tǒng)性能再有就是在使任何類型的緩存是沒有意義的。
查詢級別緩存:
使用查詢緩存,必須先使用 hibernate.cache.use_query_cache="true"屬性配置文件中激活它。如果將此屬性設(shè)置為true,讓Hibernate的在內(nèi)存中創(chuàng)建所需的高速緩存來保存查詢和標(biāo)識符集。
接下來,使用查詢緩存,可以使用Query類的setCacheable(Boolean)方法。例如:
- Session session = SessionFactory.openSession();
- Query query = session.createQuery("FROM EMPLOYEE");
- query.setCacheable(true);
- List users = query.list();
- SessionFactory.closeSession();
Hibernate也支持通過一個緩存區(qū)域的概念非常細(xì)粒度的緩存支持。緩存區(qū)是這是給定一個名稱緩存的一部分。
- Session session = SessionFactory.openSession();
- Query query = session.createQuery("FROM EMPLOYEE");
- query.setCacheable(true);
- query.setCacheRegion("employee");
- List users = query.list();
- SessionFactory.closeSession();
此代碼使用方法告訴Hibernate來存儲和查找在緩存中的員工方面的查詢。
相關(guān)文章
java創(chuàng)建多級目錄文件的實(shí)例講解
下面小編就為大家分享一篇java創(chuàng)建多級目錄文件的實(shí)例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Java代碼實(shí)現(xiàn)對properties文件有序的讀寫的示例
本篇文章主要介紹了Java代碼實(shí)現(xiàn)對properties文件有序的讀寫的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
java map轉(zhuǎn)Multipart/form-data類型body實(shí)例
這篇文章主要介紹了java map轉(zhuǎn)Multipart/form-data類型body實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Spring 事務(wù)事件監(jiān)控及實(shí)現(xiàn)原理解析
本文首先會使用實(shí)例進(jìn)行講解Spring事務(wù)事件是如何使用的,然后會講解這種使用方式的實(shí)現(xiàn)原理。感興趣的朋友跟隨小編一起看看吧2018-09-09
springboot?+mybatis?使用PageHelper實(shí)現(xiàn)分頁并帶條件模糊查詢功能
這篇文章主要介紹了springboot?+mybatis?使用PageHelper實(shí)現(xiàn)分頁并帶條件模糊查詢功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02
spring?boot+mybatis-plus配置讀寫分離的操作
這篇文章主要介紹了spring?boot+mybatis-plus配置讀寫分離的操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01
java線性表的存儲結(jié)構(gòu)及其代碼實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)筆記第一篇,線性表的存儲結(jié)構(gòu)及其代碼實(shí)現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09

