package com.hibernate.higherApplication;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Expression;
public class DurationOperator extends TestCase {
private SessionFactory sessionFactory = null;
private Session session = null;
/**
* 初始化資源
*/
protected void setUp() throws Exception {
try {
//加載類路徑下的hibernate.cfg.xml文件
Configuration config = new Configuration().configure();
//創(chuàng)建sessionFactory對象
sessionFactory = config.buildSessionFactory();
//創(chuàng)建session
session = sessionFactory.openSession();
} catch (HibernateException e) {
e.printStackTrace();
}
}
/**
* load/get方法均可以根據(jù)指定的實體類和id從數(shù)據(jù)庫讀取記錄,并返回與之對應(yīng)的實體對象。
* 區(qū)別在于:
* 1、如果未發(fā)現(xiàn)符合條件的記錄,get方法返回null,而load方法拋出一個ObjectNotFoundException
* 2、load方法可以返回實體的代理類實例,而get方法永遠直接返回實體類。
* 3、load方法可以充分利用內(nèi)部緩存和二級緩存中的現(xiàn)有數(shù)據(jù),而get方法則僅僅在內(nèi)部緩存中進行數(shù)據(jù)查找,如果
* 沒有發(fā)現(xiàn)數(shù)據(jù),將越過二級緩存,直接調(diào)用SQL完成數(shù)據(jù)讀取。
*
*/
public void loadOrGetData(){
TUser user = (TUser)session.load(TUser.class,new Integer(1));
}
/**
* 查詢性能往往是一系統(tǒng)性能表現(xiàn)的一個重要方面。
* query.list方法通過一條select SQL實現(xiàn)了查詢操作,而iterate方法,則執(zhí)行了3次selectSQL,第一次獲取了所有符合條件的記錄
* 的id,之后,在根據(jù)各個id從庫表中讀取對應(yīng)的哦記錄,這是一個典型的N+1次查詢問題。
*
* 我們進行query.list數(shù)據(jù)查詢時,即使緩存中已經(jīng)有一些符合條件的實體對象存在,我們也無法保證這些數(shù)據(jù)就是庫表中所有符合條件的數(shù)據(jù)。假設(shè)
* 第一次查詢條件是age>25,隨即緩存中就包括了所有age>25的user數(shù)據(jù);第二次查詢條件為age>20,此時緩存中雖然包含了滿足age>25d的
* 數(shù)據(jù),但這些并不是滿足條件age>20的全部數(shù)據(jù)
* 因此,query.list方法還是需要執(zhí)行一次select sql以保證查詢結(jié)果的完整性(iterate方法通過首先查詢獲取所有符合條件記錄的id,以此保證
* 查詢結(jié)果的完整性)。
* 因此,query.list方法實際上無法利用緩存,它對緩存只寫不讀。而iterate方法則可以充分發(fā)揮緩存帶來的優(yōu)勢,如果目標(biāo)數(shù)據(jù)只讀或者讀取相對
* 較為頻繁,通過這種機制可以大大減少性能上的損耗。
*/
public void queryForList(){
String hql = "from TUser where age>?";
Query query = session.createQuery(hql);
query.setInteger(1,1);
List list = query.list();
for(int i=0;i<list.size();i++){
TUser user = (TUser)list.get(i);
System.out.println("User age:"+user.getAge());
}
}
public void queryForIterate(){
String hql = "from TUser where age>?";
Query query = session.createQuery(hql);
query.setInteger(1,1);
Iterator it = query.iterate();
while(it.hasNext()){
TUser user = (TUser)it.next();
System.out.println("User age:"+user.getAge());
}
}
/**
* 大數(shù)據(jù)量的批量讀取(10W條)
* 解決方案:結(jié)合iterate方法和evict方法逐條對記錄進行處理,將內(nèi)存消耗保持在可以接受的范圍之內(nèi)。
* 在實際開發(fā)中,對于大批量數(shù)據(jù)處理,還是推薦采用SQL或存儲過程實現(xiàn),以獲得較高的性能,并保證系統(tǒng)平滑運行。
*/
public void bigDataRead(){
String hql = "from TUser where age>?";
Query query = session.createQuery(hql);
query.setInteger("age", 1);
Iterator it = query.iterate();
while(it.hasNext()){
TUser user = (TUser)it.next();
//將對象從一級緩存中移除
session.evict(user);
//二級緩存可以設(shè)定最大數(shù)據(jù)緩存數(shù)量,達到峰值時會自動對緩存中的較老數(shù)據(jù)進行廢除,但是我們這里還是通過
//編碼指定將對象從二級緩存中移除,這有助保持緩存的數(shù)據(jù)有效性。
sessionFactory.evict(TUser.class,user.getId());
}
}
/**
* Query Cache彌補了find方法的不足,QueryCache中緩存的SQL及其結(jié)果及并非永遠存在,當(dāng)Hibernate發(fā)現(xiàn)此SQL對應(yīng)的庫表發(fā)生變動,
* 會自動將Query Cache中對應(yīng)表的SQL緩存廢除。因此Query Cache只在特定的情況下產(chǎn)生作用:
* 1、完全相同的select SQL重復(fù)執(zhí)行。
* 2、在2次查詢之間,此select SQL對應(yīng)的庫表沒有發(fā)生過改變。
*/
public void queryForQueryCache(){
String hql = "from TUser where age>?";
Query query = session.createQuery(hql);
query.setInteger(1, 1);
//除了在這里設(shè)置QueryCache外,還要在hibernate.cfg.xml中進行設(shè)置
//<property name="hibernate.cache.use_query_cache">true</property>
query.setCacheable(true);
List userList = query.list();
}
/**
* 所謂延遲加載,就是在需要數(shù)據(jù)的時候,才真正執(zhí)行數(shù)據(jù)加載操作。
* 延遲加載實現(xiàn)主要針對:
* 1、實體對象:通過class的lazy屬性,我們可以打開實體對象的延遲加載功能。
* 2、集合
*/
public void queryForEntityLazy(){
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list();
TUser user = (TUser)userList.get(0);
//雖然使用了延遲加載,但是我們可以通過hibernate的初始化方法進行強制加載,這樣即使session關(guān)閉之后,關(guān)聯(lián)的對象仍讓可以使用
Hibernate.initialize(user.getAddresses());
System.out.println("User name=>"+user.getAge());
Set hset =user.getAddresses();
TAddresses addr = (TAddresses)hset.toArray()[0];
System.out.println(addr.getAddress());
session.close();
}
/**
* 關(guān)閉資源
*/
protected void tearDown() throws Exception {
try{
session.close();
}catch(HibernateException e){
e.printStackTrace();
}
}
}
posted @
2010-01-02 15:27 王永慶 閱讀(363) |
評論 (0) |
編輯 收藏
基于Java的緩存實現(xiàn),最簡單的方式莫過于對集合類數(shù)據(jù)類型進行封裝。Hibernate提供了基于Hashtable的緩存實現(xiàn)機制,不過,由于其性能和功能上的局限,僅供開發(fā)調(diào)試中使用。同時,Hibernate還提供了面向第三方緩存實現(xiàn)的接口,如:
HashTable--------------------------------net.sf.hibernate.cache.HashtableCacheProvider
1、JSC
2、EHCache->默認(rèn)的二級Cache實現(xiàn)。--------net.sf.encache.hibernate.Provider
3、OSCache-------------------------------net.sf.hibernate.cache.OSCacheProvider
4、JBoss Cache->分布式緩存---------------net.sf.hibernate.cache.TreeCacheProvider
5、SwarmCache----------------------------net.sf.hibernate.cache.SwarmCacheProvider
相對于JSC而言,EHCache更加穩(wěn)定,并具備更好的混存調(diào)度性能,其缺陷是目前還無法做到分布式緩存。
首先設(shè)置hibernate.cfg.xml然后設(shè)置ehcache.xml最后設(shè)置緩存策略。
緩存同步策略決定了數(shù)據(jù)對象在緩存中的存取規(guī)則。為了使得緩存調(diào)度遵循正確的應(yīng)用級事物隔離機制,我們必須為每個實體類指定相應(yīng)的緩存同步策略。Hibernate提供4種內(nèi)置的緩存同步策略:
1、read-only:只讀。對于不會發(fā)生改變的數(shù)據(jù),可使用只讀型緩存。
2、nonstrict-read-write:如果程序?qū)Σl(fā)訪問下的數(shù)據(jù)同步要求不是非常嚴(yán)格,且數(shù)據(jù)更新操作頻率較低,可以采用本選項。
3、read-write:嚴(yán)格可讀寫緩存。
4、transactional:事務(wù)型緩存,必須運行在JTA事物環(huán)境中。
JDBC事物由Connection管理,也就是說,事務(wù)管理實際上是在JDBC Connection中實現(xiàn)。事務(wù)周期限于Connection的生命周期之類。同樣,對于基于JDBC Transaction的Hibernate事務(wù)管理機制而言,事物管理在Session所以托的JDBCConnection中實現(xiàn),事務(wù)周期限于Session的生命周期。
JTA事物管理則由JTA容器實現(xiàn),JTA容器對當(dāng)前加入事物的眾多Connection進行調(diào)度,實現(xiàn)其事務(wù)性要求。JTA的事物周期可橫跨多個JDBC Connectin生命周期。同樣對于基于JTA事務(wù)的Hibernate而言,JTA事物橫跨多個Session.
Hibernate支持2種鎖機制:即通常所說的悲觀鎖和樂觀鎖。
悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制。典型的悲觀鎖調(diào)用:
select * from account where name=="Erica" for update
package com.hibernate.higherApplication;
import java.util.List;
import junit.framework.TestCase;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Expression;
public class LockOperator extends TestCase {
private Session session = null;
/**
* 初始化資源
*/
protected void setUp() throws Exception {
try {
//加載類路徑下的hibernate.cfg.xml文件
Configuration config = new Configuration().configure();
//創(chuàng)建sessionFactory對象
SessionFactory sessionFactory = config.buildSessionFactory();
//創(chuàng)建session
session = sessionFactory.openSession();
} catch (HibernateException e) {
e.printStackTrace();
}
}
/**
* 悲觀鎖
* Hibernate的加鎖模式有:
* 1、LockMode.NONE:無鎖機制
* 2、LockMode.WRITE:Hibernate在Insert和Update記錄的時候會自動獲取
* 3、LockMode.READ:Hibernate在讀取記錄的時候會自動獲取
* 上述3種鎖機制為了保證update過程中對象不會被外界修改,在目標(biāo)對象上加鎖,與數(shù)據(jù)庫無關(guān)
* 4、LockMode.UPGRADE:利用數(shù)據(jù)庫的for update子句加鎖
* 5、LockMode.UPGRADE_NOWAIT:oracle的特定實現(xiàn)
* 注意:只有在查詢開始之前設(shè)定加鎖,才會真正通過數(shù)據(jù)庫的鎖機制進行加鎖處理。
*/
public void addPessimismLock(){
String hqlStr = "from TUser as user where user.name='Erica'";
Query query = session.createQuery(hqlStr);
query.setLockMode("user",LockMode.UPGRADE);//多所有返回的user對象加鎖
List userList = query.list();//執(zhí)行查詢
}
/**
* 樂觀鎖
* 數(shù)據(jù)版本:即為數(shù)據(jù)增加一個版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個version字段來實現(xiàn)。
* 讀取出數(shù)據(jù)時,將此版本號一同讀出,之后更新時,對此版本號加1.此時,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫對應(yīng)記錄的當(dāng)前版本信息
* 進行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
*
* Hibernate在其數(shù)據(jù)訪問引擎中內(nèi)置了樂觀鎖實現(xiàn)。如果不考慮外部系統(tǒng)對數(shù)據(jù)庫的更新操作,利用Hibernate提供的透明化樂觀鎖
* 實現(xiàn),將大大提升我們的生產(chǎn)力。見配置文件T_USER.hbm.xml
* 樂觀鎖機制避免了長事務(wù)中的數(shù)據(jù)加鎖開銷,大大提升了大并發(fā)量下的系統(tǒng)整體性能表象。
*
*/
public void addOptimismLock(){
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list();
TUser user = (TUser)userList.get(0);
Transaction tx = session.beginTransaction();
user.setVersion(1);
tx.commit();
}
/**
* 關(guān)閉資源
*/
protected void tearDown() throws Exception {
try{
session.close();
}catch(HibernateException e){
e.printStackTrace();
}
}
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
none:無樂觀鎖
version:通過版本機制實現(xiàn)樂觀鎖
dirty:通過檢查發(fā)生變動過的屬性實現(xiàn)樂觀鎖
all通過檢查所有屬性實現(xiàn)樂觀鎖
-->
<class
name="org.hibernate.sample.TUSER"
table="t_user"
dynamic-update="true"
dynamic-insert="true"
optimistic-lock="version"
lazy="true"
>
<id
name="id"
column="id"
type="java.lang.Integer"
>
<generator class="native">
</generator>
</id>
<version name="version" column="version" type="java.lang.Integer">
</version>
<set name="addresses"
table="t_address"
lazy="true"
inverse="false"
cascade="all"
>
<key
column="user_id"
>
</key>
<one-to-many class=""/>
</set>
</class>
</hibernate-mapping>
posted @
2010-01-02 15:25 王永慶 閱讀(561) |
評論 (0) |
編輯 收藏