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();
//創建sessionFactory對象
sessionFactory = config.buildSessionFactory();
//創建session
session = sessionFactory.openSession();
} catch (HibernateException e) {
e.printStackTrace();
}
}
/**
* load/get方法均可以根據指定的實體類和id從數據庫讀取記錄,并返回與之對應的實體對象。
* 區別在于:
* 1、如果未發現符合條件的記錄,get方法返回null,而load方法拋出一個ObjectNotFoundException
* 2、load方法可以返回實體的代理類實例,而get方法永遠直接返回實體類。
* 3、load方法可以充分利用內部緩存和二級緩存中的現有數據,而get方法則僅僅在內部緩存中進行數據查找,如果
* 沒有發現數據,將越過二級緩存,直接調用SQL完成數據讀取。
*
*/
public void loadOrGetData(){
TUser user = (TUser)session.load(TUser.class,new Integer(1));
}
/**
* 查詢性能往往是一系統性能表現的一個重要方面。
* query.list方法通過一條select SQL實現了查詢操作,而iterate方法,則執行了3次selectSQL,第一次獲取了所有符合條件的記錄
* 的id,之后,在根據各個id從庫表中讀取對應的哦記錄,這是一個典型的N+1次查詢問題。
*
* 我們進行query.list數據查詢時,即使緩存中已經有一些符合條件的實體對象存在,我們也無法保證這些數據就是庫表中所有符合條件的數據。假設
* 第一次查詢條件是age>25,隨即緩存中就包括了所有age>25的user數據;第二次查詢條件為age>20,此時緩存中雖然包含了滿足age>25d的
* 數據,但這些并不是滿足條件age>20的全部數據
* 因此,query.list方法還是需要執行一次select sql以保證查詢結果的完整性(iterate方法通過首先查詢獲取所有符合條件記錄的id,以此保證
* 查詢結果的完整性)。
* 因此,query.list方法實際上無法利用緩存,它對緩存只寫不讀。而iterate方法則可以充分發揮緩存帶來的優勢,如果目標數據只讀或者讀取相對
* 較為頻繁,通過這種機制可以大大減少性能上的損耗。
*/
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());
}
}
/**
* 大數據量的批量讀取(10W條)
* 解決方案:結合iterate方法和evict方法逐條對記錄進行處理,將內存消耗保持在可以接受的范圍之內。
* 在實際開發中,對于大批量數據處理,還是推薦采用SQL或存儲過程實現,以獲得較高的性能,并保證系統平滑運行。
*/
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);
//二級緩存可以設定最大數據緩存數量,達到峰值時會自動對緩存中的較老數據進行廢除,但是我們這里還是通過
//編碼指定將對象從二級緩存中移除,這有助保持緩存的數據有效性。
sessionFactory.evict(TUser.class,user.getId());
}
}
/**
* Query Cache彌補了find方法的不足,QueryCache中緩存的SQL及其結果及并非永遠存在,當Hibernate發現此SQL對應的庫表發生變動,
* 會自動將Query Cache中對應表的SQL緩存廢除。因此Query Cache只在特定的情況下產生作用:
* 1、完全相同的select SQL重復執行。
* 2、在2次查詢之間,此select SQL對應的庫表沒有發生過改變。
*/
public void queryForQueryCache(){
String hql = "from TUser where age>?";
Query query = session.createQuery(hql);
query.setInteger(1, 1);
//除了在這里設置QueryCache外,還要在hibernate.cfg.xml中進行設置
//<property name="hibernate.cache.use_query_cache">true</property>
query.setCacheable(true);
List userList = query.list();
}
/**
* 所謂延遲加載,就是在需要數據的時候,才真正執行數據加載操作。
* 延遲加載實現主要針對:
* 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關閉之后,關聯的對象仍讓可以使用
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();
}
/**
* 關閉資源
*/
protected void tearDown() throws Exception {
try{
session.close();
}catch(HibernateException e){
e.printStackTrace();
}
}
}
posted @
2010-01-02 15:27 王永慶 閱讀(363) |
評論 (0) |
編輯 收藏
基于Java的緩存實現,最簡單的方式莫過于對集合類數據類型進行封裝。Hibernate提供了基于Hashtable的緩存實現機制,不過,由于其性能和功能上的局限,僅供開發調試中使用。同時,Hibernate還提供了面向第三方緩存實現的接口,如:
HashTable--------------------------------net.sf.hibernate.cache.HashtableCacheProvider
1、JSC
2、EHCache->默認的二級Cache實現。--------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更加穩定,并具備更好的混存調度性能,其缺陷是目前還無法做到分布式緩存。
首先設置hibernate.cfg.xml然后設置ehcache.xml最后設置緩存策略。
緩存同步策略決定了數據對象在緩存中的存取規則。為了使得緩存調度遵循正確的應用級事物隔離機制,我們必須為每個實體類指定相應的緩存同步策略。Hibernate提供4種內置的緩存同步策略:
1、read-only:只讀。對于不會發生改變的數據,可使用只讀型緩存。
2、nonstrict-read-write:如果程序對并發訪問下的數據同步要求不是非常嚴格,且數據更新操作頻率較低,可以采用本選項。
3、read-write:嚴格可讀寫緩存。
4、transactional:事務型緩存,必須運行在JTA事物環境中。
JDBC事物由Connection管理,也就是說,事務管理實際上是在JDBC Connection中實現。事務周期限于Connection的生命周期之類。同樣,對于基于JDBC Transaction的Hibernate事務管理機制而言,事物管理在Session所以托的JDBCConnection中實現,事務周期限于Session的生命周期。
JTA事物管理則由JTA容器實現,JTA容器對當前加入事物的眾多Connection進行調度,實現其事務性要求。JTA的事物周期可橫跨多個JDBC Connectin生命周期。同樣對于基于JTA事務的Hibernate而言,JTA事物橫跨多個Session.
Hibernate支持2種鎖機制:即通常所說的悲觀鎖和樂觀鎖。
悲觀鎖的實現,往往依靠數據庫提供的鎖機制。典型的悲觀鎖調用:
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();
//創建sessionFactory對象
SessionFactory sessionFactory = config.buildSessionFactory();
//創建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過程中對象不會被外界修改,在目標對象上加鎖,與數據庫無關
* 4、LockMode.UPGRADE:利用數據庫的for update子句加鎖
* 5、LockMode.UPGRADE_NOWAIT:oracle的特定實現
* 注意:只有在查詢開始之前設定加鎖,才會真正通過數據庫的鎖機制進行加鎖處理。
*/
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();//執行查詢
}
/**
* 樂觀鎖
* 數據版本:即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個version字段來實現。
* 讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加1.此時,將提交數據的版本數據與數據庫對應記錄的當前版本信息
* 進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。
*
* Hibernate在其數據訪問引擎中內置了樂觀鎖實現。如果不考慮外部系統對數據庫的更新操作,利用Hibernate提供的透明化樂觀鎖
* 實現,將大大提升我們的生產力。見配置文件T_USER.hbm.xml
* 樂觀鎖機制避免了長事務中的數據加鎖開銷,大大提升了大并發量下的系統整體性能表象。
*
*/
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();
}
/**
* 關閉資源
*/
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:通過版本機制實現樂觀鎖
dirty:通過檢查發生變動過的屬性實現樂觀鎖
all通過檢查所有屬性實現樂觀鎖
-->
<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) |
編輯 收藏
實體對象,特指Hibernate O/R映射關系中的域對象。實體對象生命周期中的3種狀態
1、Transient(自由狀態):所謂Transient,即實體對象在內存中的自由存在,它與數據庫中的記錄無關。
2、Persistent(持久狀態):即實體對象處于由Hibernate框架所管理的狀態。
3、Detached(游離狀態):處于Persistent狀態的對象,其對應的Session實例關閉之后,那么,此對象就處于"Detached"狀態。
Transient狀態的user對象與庫表的數據缺乏對應關系,而Detached狀態的user對象,卻在庫表中存在對應的記錄,只不過由于Detached對象脫離了session這個數據操作平臺,其狀態的變化無法更新到庫表中的對應記錄。
處于Transient和Detached狀態的對象統稱為值對象(VO),而處于Persistent狀態的對象稱為持久對象(PO).這是站在實體對象是否被納入Hibernate實體管理容器的立場加以區分的,非管理的實體對象統稱為VO,而被管理的實體對象稱為PO.
VO與PO的主要區別在于:
1、VO是相對獨立的實體對象,處于非管理狀態。
2、PO是由Hibernate納入其實體管理容器的對象,它代表了與數據庫中某條記錄對應的Hibernate實體,PO的變化在事務提交時將反映到實際數據庫中
3、如果一個PO與其對應的Session實例分離,那么此時,它又會變成一個VO。
不覆蓋equals/hashCode方法的情況下我們要面對的問題:實體對象的跨session識別。解決辦法一個是實現所謂的值比對,即在equals/hashCode方法中,對實體類的所有屬性值進行比對.除了值比對,還有另外一種基于業務邏輯的對象判定方式業務關鍵信息判定。
tx.commint();方法中會調用session.flush()方法,在flush()方法中會執行2個主要任務
1、flushEverything();//刷新所有數據
2、execute(0);//執行數據庫SQL完成持久化動作。
數據緩存:在特定硬件基礎上緩存往往是提升系統性能的關鍵因素。緩存是數據庫數據在內存中的臨時容器,它包含了庫表數據在內存中的臨時拷貝,位于數據庫與數據訪問層之間。ORM在進行數據讀取時,會根據其緩存管理策略,首先在緩存中查詢,如果在緩存中發現所需數據,則直接以此數據作為查詢結果加以利用,從而避免了數據庫調用的性能開銷。
相對內存操作而言,數據庫調用是一個代價高昂的過程,對于典型企業及應用結構,數據庫往往與應用服務器位于不同的物理服務器,這也就意味著每次數據庫訪問都是一次遠程調用,Socket的創建與銷毀,數據的打包拆包,數據庫執行查詢命令,網絡傳輸上的延時,這些消耗都給系統整體性能造成了嚴重影響。
ORM的數據緩存應包含如下幾個層次:
1、事務級緩存:事務級緩存是基于Session生命周期實現的,每個Session會在內部維持一個數據緩存,此緩存隨著Session的創建而存在,因此也成為Session Level Cache(內部緩存)
2、應用級/進程級緩存:在某個應用中,或者應用中某個獨立數據訪問子集中的共享緩存。此緩存可由多個事物共享。在Hibernate中,應用級緩存在SessinFactory層實現,所有由此SessionFactory創建的Session實例共享此緩存。多實例并發運行的環境要特別小心進程級緩存的調用。
3、分布式緩存:分布式緩存由多個應用級緩存實例組成集群,通過某種遠程機制實現各個緩存實例間的數據同步,任何一個實例的數據修改操作,將導致整個集群間的數據狀態同步。由于多個實例間的數據同步機制,每個緩存實例發生的變動都會復制到其余所有節點中,這樣的遠程同步開銷不可忽視。
Hibernate數據緩存分為2個層次,1、內部緩存2、二級緩存hibernate中,緩存將在以下情況中發揮作用:
1、通過ID加載數據時
這包括了根據id查詢數據的Session.load方法,以及Session.ierate等批量查詢方法
2、延遲加載
Session在進行數據查詢操作時,會首先在自身內部的一級緩存中進行查找,如果一級緩存未能命中,則將在二級緩存中查詢,如果二級緩存命中,則以此數據作為結果返回。
如果數據滿足以下條件,則可將其納入緩存管理
1、數據不會被第三方應用修改
2、數據大小在可接受的范圍之內
3、數據更新頻率較低
4、同一數據可能會被系統頻繁引用
5、非關鍵數據(關鍵數據,如金融賬戶數據)
Hibernate本身并未提供二級緩存的產品化實現(只是提供了一個基于Hashtable的簡單緩存以供調試),而是為眾多的第三方緩存組件提供了接入接口,我們可以根據實際情況選擇不同的緩存實現版本。
posted @
2009-12-22 15:01 王永慶 閱讀(219) |
評論 (0) |
編輯 收藏
比較字符串是否相等使用equals方法
使用"=="與equals到底有哪些不同?
equals:可以比較內容,是2個字符串內容的比較。
==:數值比較,比較的是內存地址的值是否相等。
一個字符串就是String類的匿名對象。
String name1 = new String("wyq");->開辟了2個空間,其中一個是垃圾空間。
String name2 = "wyq";->開辟了一個空間,所以應該選擇它。
String的另一個特殊之處:String使用了Java中的共享模式,它只要發現在內存中有這塊數據,不會在內存中重新生成。
String類中的內容一旦聲明則不可改變。
StringBuffer與String的本質區別,在于StringBuffer可以改變。
this可以調用本類中的屬性,也可以調用本類中的方法(含構造方法this())。
注意:構造方法本身必須在首行被使用,為了給類中的屬性初始化。
this調用屬性、本類方法、構造方法這三點是this的基本應用,也是最常用的,但是以上三點實際上可以綜合成一點---表示當前對象。
this表示當前對象主要應用在一點:用于進行對象的比較。

public boolean compare(Person p1)
{
boolean flag = false;
Person p2 = this;
if(p1.name.equals(p2.name)&&p1.age==p2.age)

{
flag = true;
}
return flag;
}
posted @
2009-12-08 09:56 王永慶 閱讀(191) |
評論 (0) |
編輯 收藏