詳解Java的Hibernate框架中的緩存與原生SQL語句的應用。本站提示廣大學習愛好者:(詳解Java的Hibernate框架中的緩存與原生SQL語句的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java的Hibernate框架中的緩存與原生SQL語句的應用正文
Hibernate緩存
緩存是一切關於運用法式的機能優化和它位於運用法式和數據庫之間,以免數據庫拜訪屢次,讓機能症結型運用法式有更好的表示。
緩存對Hibernate很主要,它采取了多級緩存計劃下文所述:
第一級緩存:
第一級緩存是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迫使選擇一個緩存供給全部運用法式。
在指定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();
此代碼應用辦法告知Hibernate來存儲和查找在緩存中的員工方面的查詢。
Hibernate原生SQL
可使用原生SQL來表達數據庫查詢,假如想應用數據庫獨有的功效,如查詢提醒或許Oracle中的CONNECT症結字。 Hibernate3.x許可應用手寫SQL語句,包含存儲進程,一切的創立,更新,刪除和load操作。
運用法式將從會話創立一個原生SQL查詢(Session接口上)createSQLQuery()辦法:
public SQLQuery createSQLQuery(String sqlString) throws HibernateException
當傳遞一個包括SQL查詢到createSQLQuery()辦法,可以將SQL成果與任何現有的Hibernate實體,聯接,或許一個標量成果應用addEntity()辦法,addJoin(),和addScalar()辦法聯系關系的字符串。
標量查詢:
最根本的SQL查詢是從一個或多個表中獲得標量(數值)的列表。以下是語法應用原生SQL標量的值:
String sql = "SELECT first_name, salary FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); List results = query.list();
實體的查詢:
下面的查詢都是前往標量值,也就是從resultset中前往的“裸”數據。以下是語法經由過程addEntity()辦法來從原生SQL查詢取得實體對象作為一個全體。
String sql = "SELECT * FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); List results = query.list();
定名SQL查詢:
以下是語法經由過程addEntity()辦法來從原生SQL查詢取得實體對象和應用定名SQL查詢。
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); query.setParameter("employee_id", 10); List results = query.list();
Native SQL 例子:
斟酌上面的POJO類:
public class Employee { private int id; private String firstName; private String lastName; private int salary; public Employee() {} public Employee(String fname, String lname, int salary) { this.firstName = fname; this.lastName = lname; this.salary = salary; } 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; } }
讓我們創立上面的EMPLOYEE表來存儲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) );
以下將被映照文件。
<?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> <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>
最初,我們將創立運用法式類的main()辦法來運轉,我們將應用原生SQL查詢的運用法式:
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.SQLQuery; import org.hibernate.Criteria; import org.hibernate.Hibernate; import org.hibernate.cfg.Configuration; public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new Configuration().configure().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", 2000); Integer empID2 = ME.addEmployee("Daisy", "Das", 5000); Integer empID3 = ME.addEmployee("John", "Paul", 5000); Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000); /* List down employees and their salary using Scalar Query */ ME.listEmployeesScalar(); /* List down complete employees information using Entity Query */ ME.listEmployeesEntity(); } /* 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(fname, lname, 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 using Scalar Query */ public void listEmployeesScalar( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); String sql = "SELECT first_name, salary FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); List data = query.list(); for(Object object : data) { Map row = (Map)object; System.out.print("First Name: " + row.get("first_name")); System.out.println(", Salary: " + row.get("salary")); } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to READ all the employees using Entity Query */ public void listEmployeesEntity( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); String sql = "SELECT * FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); List employees = query.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(); } } }
編譯和履行:
上面是步調來編譯並運轉上述運用法式。請確保在停止的編譯和履行之前,恰當地設置PATH和CLASSPATH。
履行ManageEmployee二進制文件來運轉法式。
會獲得以下成果,並記載將在EMPLOYEE表中創立。
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........ First Name: Zara, Salary: 2000 First Name: Daisy, Salary: 5000 First Name: John, Salary: 5000 First Name: Mohd, Salary: 3000 First Name: Zara Last Name: Ali Salary: 2000 First Name: Daisy Last Name: Das Salary: 5000 First Name: John Last Name: Paul Salary: 5000 First Name: Mohd Last Name: Yasee Salary: 3000
假如檢討EMPLOYEE表,它應當記載下已:
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+ | id | first_name | last_name | salary | +----+------------+-----------+--------+ | 26 | Zara | Ali | 2000 | | 27 | Daisy | Das | 5000 | | 28 | John | Paul | 5000 | | 29 | Mohd | Yasee | 3000 | +----+------------+-----------+--------+ 4 rows in set (0.00 sec)