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方法永遠(yuǎn)直接返回實體類。
* 3、load方法可以充分利用內(nèi)部緩存和二級緩存中的現(xiàn)有數(shù)據(jù),而get方法則僅僅在內(nèi)部緩存中進(jìn)行數(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次查詢問題。
*
* 我們進(jìn)行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ù)只讀或者讀取相對
* 較為頻繁,通過這種機(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方法逐條對記錄進(jìn)行處理,將內(nèi)存消耗保持在可以接受的范圍之內(nèi)。
* 在實際開發(fā)中,對于大批量數(shù)據(jù)處理,還是推薦采用SQL或存儲過程實現(xiàn),以獲得較高的性能,并保證系統(tǒng)平滑運(yùn)行。
*/
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ù)量,達(dá)到峰值時會自動對緩存中的較老數(shù)據(jù)進(jìn)行廢除,但是我們這里還是通過
//編碼指定將對象從二級緩存中移除,這有助保持緩存的數(shù)據(jù)有效性。
sessionFactory.evict(TUser.class,user.getId());
}
}
/**
* Query Cache彌補(bǔ)了find方法的不足,QueryCache中緩存的SQL及其結(jié)果及并非永遠(yuǎn)存在,當(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中進(jìn)行設(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的初始化方法進(jìn)行強(qiáng)制加載,這樣即使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 王永慶 閱讀(364) |
評論 (0) |
編輯 收藏
基于Java的緩存實現(xiàn),最簡單的方式莫過于對集合類數(shù)據(jù)類型進(jìn)行封裝。Hibernate提供了基于Hashtable的緩存實現(xiàn)機(jī)制,不過,由于其性能和功能上的局限,僅供開發(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)用級事物隔離機(jī)制,我們必須為每個實體類指定相應(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ù)型緩存,必須運(yùn)行在JTA事物環(huán)境中。
JDBC事物由Connection管理,也就是說,事務(wù)管理實際上是在JDBC Connection中實現(xiàn)。事務(wù)周期限于Connection的生命周期之類。同樣,對于基于JDBC Transaction的Hibernate事務(wù)管理機(jī)制而言,事物管理在Session所以托的JDBCConnection中實現(xiàn),事務(wù)周期限于Session的生命周期。
JTA事物管理則由JTA容器實現(xiàn),JTA容器對當(dāng)前加入事物的眾多Connection進(jìn)行調(diào)度,實現(xiàn)其事務(wù)性要求。JTA的事物周期可橫跨多個JDBC Connectin生命周期。同樣對于基于JTA事務(wù)的Hibernate而言,JTA事物橫跨多個Session.
Hibernate支持2種鎖機(jī)制:即通常所說的悲觀鎖和樂觀鎖。
悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機(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:無鎖機(jī)制
* 2、LockMode.WRITE:Hibernate在Insert和Update記錄的時候會自動獲取
* 3、LockMode.READ:Hibernate在讀取記錄的時候會自動獲取
* 上述3種鎖機(jī)制為了保證update過程中對象不會被外界修改,在目標(biāo)對象上加鎖,與數(shù)據(jù)庫無關(guān)
* 4、LockMode.UPGRADE:利用數(shù)據(jù)庫的for update子句加鎖
* 5、LockMode.UPGRADE_NOWAIT:oracle的特定實現(xiàn)
* 注意:只有在查詢開始之前設(shè)定加鎖,才會真正通過數(shù)據(jù)庫的鎖機(jī)制進(jìn)行加鎖處理。
*/
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)前版本信息
* 進(jìn)行比對,如果提交的數(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
* 樂觀鎖機(jī)制避免了長事務(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:通過版本機(jī)制實現(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 王永慶 閱讀(562) |
評論 (0) |
編輯 收藏
實體對象,特指Hibernate O/R映射關(guān)系中的域?qū)ο蟆嶓w對象生命周期中的3種狀態(tài)
1、Transient(自由狀態(tài)):所謂Transient,即實體對象在內(nèi)存中的自由存在,它與數(shù)據(jù)庫中的記錄無關(guān)。
2、Persistent(持久狀態(tài)):即實體對象處于由Hibernate框架所管理的狀態(tài)。
3、Detached(游離狀態(tài)):處于Persistent狀態(tài)的對象,其對應(yīng)的Session實例關(guān)閉之后,那么,此對象就處于"Detached"狀態(tài)。
Transient狀態(tài)的user對象與庫表的數(shù)據(jù)缺乏對應(yīng)關(guān)系,而Detached狀態(tài)的user對象,卻在庫表中存在對應(yīng)的記錄,只不過由于Detached對象脫離了session這個數(shù)據(jù)操作平臺,其狀態(tài)的變化無法更新到庫表中的對應(yīng)記錄。
處于Transient和Detached狀態(tài)的對象統(tǒng)稱為值對象(VO),而處于Persistent狀態(tài)的對象稱為持久對象(PO).這是站在實體對象是否被納入Hibernate實體管理容器的立場加以區(qū)分的,非管理的實體對象統(tǒng)稱為VO,而被管理的實體對象稱為PO.
VO與PO的主要區(qū)別在于:
1、VO是相對獨立的實體對象,處于非管理狀態(tài)。
2、PO是由Hibernate納入其實體管理容器的對象,它代表了與數(shù)據(jù)庫中某條記錄對應(yīng)的Hibernate實體,PO的變化在事務(wù)提交時將反映到實際數(shù)據(jù)庫中
3、如果一個PO與其對應(yīng)的Session實例分離,那么此時,它又會變成一個VO。
不覆蓋equals/hashCode方法的情況下我們要面對的問題:實體對象的跨session識別。解決辦法一個是實現(xiàn)所謂的值比對,即在equals/hashCode方法中,對實體類的所有屬性值進(jìn)行比對.除了值比對,還有另外一種基于業(yè)務(wù)邏輯的對象判定方式業(yè)務(wù)關(guān)鍵信息判定。
tx.commint();方法中會調(diào)用session.flush()方法,在flush()方法中會執(zhí)行2個主要任務(wù)
1、flushEverything();//刷新所有數(shù)據(jù)
2、execute(0);//執(zhí)行數(shù)據(jù)庫SQL完成持久化動作。
數(shù)據(jù)緩存:在特定硬件基礎(chǔ)上緩存往往是提升系統(tǒng)性能的關(guān)鍵因素。緩存是數(shù)據(jù)庫數(shù)據(jù)在內(nèi)存中的臨時容器,它包含了庫表數(shù)據(jù)在內(nèi)存中的臨時拷貝,位于數(shù)據(jù)庫與數(shù)據(jù)訪問層之間。ORM在進(jìn)行數(shù)據(jù)讀取時,會根據(jù)其緩存管理策略,首先在緩存中查詢,如果在緩存中發(fā)現(xiàn)所需數(shù)據(jù),則直接以此數(shù)據(jù)作為查詢結(jié)果加以利用,從而避免了數(shù)據(jù)庫調(diào)用的性能開銷。
相對內(nèi)存操作而言,數(shù)據(jù)庫調(diào)用是一個代價高昂的過程,對于典型企業(yè)及應(yīng)用結(jié)構(gòu),數(shù)據(jù)庫往往與應(yīng)用服務(wù)器位于不同的物理服務(wù)器,這也就意味著每次數(shù)據(jù)庫訪問都是一次遠(yuǎn)程調(diào)用,Socket的創(chuàng)建與銷毀,數(shù)據(jù)的打包拆包,數(shù)據(jù)庫執(zhí)行查詢命令,網(wǎng)絡(luò)傳輸上的延時,這些消耗都給系統(tǒng)整體性能造成了嚴(yán)重影響。
ORM的數(shù)據(jù)緩存應(yīng)包含如下幾個層次:
1、事務(wù)級緩存:事務(wù)級緩存是基于Session生命周期實現(xiàn)的,每個Session會在內(nèi)部維持一個數(shù)據(jù)緩存,此緩存隨著Session的創(chuàng)建而存在,因此也成為Session Level Cache(內(nèi)部緩存)
2、應(yīng)用級/進(jìn)程級緩存:在某個應(yīng)用中,或者應(yīng)用中某個獨立數(shù)據(jù)訪問子集中的共享緩存。此緩存可由多個事物共享。在Hibernate中,應(yīng)用級緩存在SessinFactory層實現(xiàn),所有由此SessionFactory創(chuàng)建的Session實例共享此緩存。多實例并發(fā)運(yùn)行的環(huán)境要特別小心進(jìn)程級緩存的調(diào)用。
3、分布式緩存:分布式緩存由多個應(yīng)用級緩存實例組成集群,通過某種遠(yuǎn)程機(jī)制實現(xiàn)各個緩存實例間的數(shù)據(jù)同步,任何一個實例的數(shù)據(jù)修改操作,將導(dǎo)致整個集群間的數(shù)據(jù)狀態(tài)同步。由于多個實例間的數(shù)據(jù)同步機(jī)制,每個緩存實例發(fā)生的變動都會復(fù)制到其余所有節(jié)點中,這樣的遠(yuǎn)程同步開銷不可忽視。
Hibernate數(shù)據(jù)緩存分為2個層次,1、內(nèi)部緩存2、二級緩存hibernate中,緩存將在以下情況中發(fā)揮作用:
1、通過ID加載數(shù)據(jù)時
這包括了根據(jù)id查詢數(shù)據(jù)的Session.load方法,以及Session.ierate等批量查詢方法
2、延遲加載
Session在進(jìn)行數(shù)據(jù)查詢操作時,會首先在自身內(nèi)部的一級緩存中進(jìn)行查找,如果一級緩存未能命中,則將在二級緩存中查詢,如果二級緩存命中,則以此數(shù)據(jù)作為結(jié)果返回。
如果數(shù)據(jù)滿足以下條件,則可將其納入緩存管理
1、數(shù)據(jù)不會被第三方應(yīng)用修改
2、數(shù)據(jù)大小在可接受的范圍之內(nèi)
3、數(shù)據(jù)更新頻率較低
4、同一數(shù)據(jù)可能會被系統(tǒng)頻繁引用
5、非關(guān)鍵數(shù)據(jù)(關(guān)鍵數(shù)據(jù),如金融賬戶數(shù)據(jù))
Hibernate本身并未提供二級緩存的產(chǎn)品化實現(xiàn)(只是提供了一個基于Hashtable的簡單緩存以供調(diào)試),而是為眾多的第三方緩存組件提供了接入接口,我們可以根據(jù)實際情況選擇不同的緩存實現(xiàn)版本。
posted @
2009-12-22 15:01 王永慶 閱讀(219) |
評論 (0) |
編輯 收藏
比較字符串是否相等使用equals方法
使用"=="與equals到底有哪些不同?
equals:可以比較內(nèi)容,是2個字符串內(nèi)容的比較。
==:數(shù)值比較,比較的是內(nèi)存地址的值是否相等。
一個字符串就是String類的匿名對象。
String name1 = new String("wyq");->開辟了2個空間,其中一個是垃圾空間。
String name2 = "wyq";->開辟了一個空間,所以應(yīng)該選擇它。
String的另一個特殊之處:String使用了Java中的共享模式,它只要發(fā)現(xiàn)在內(nèi)存中有這塊數(shù)據(jù),不會在內(nèi)存中重新生成。
String類中的內(nèi)容一旦聲明則不可改變。
StringBuffer與String的本質(zhì)區(qū)別,在于StringBuffer可以改變。
this可以調(diào)用本類中的屬性,也可以調(diào)用本類中的方法(含構(gòu)造方法this())。
注意:構(gòu)造方法本身必須在首行被使用,為了給類中的屬性初始化。
this調(diào)用屬性、本類方法、構(gòu)造方法這三點是this的基本應(yīng)用,也是最常用的,但是以上三點實際上可以綜合成一點---表示當(dāng)前對象。
this表示當(dāng)前對象主要應(yīng)用在一點:用于進(jìn)行對象的比較。

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 王永慶 閱讀(192) |
評論 (0) |
編輯 收藏
在軟件中,要么全有要么全無的操作成為事務(wù)。事務(wù)允許你把幾個操作組成一個單一的工作單元,這個工作單元要么全部發(fā)生要么全部不發(fā)生。如果每件事都順利,那么這個事務(wù)是成功的。但是如果任何一件事情出錯的話,那么已經(jīng)發(fā)生的行為就被清除掉,就像什么事情都沒發(fā)生一樣。
Spring對事務(wù)管理有豐富的支持,程序控制的和聲明式的。
原子性(Atomic):事務(wù)由一個或多個行為綁定在一起組成,好像是一個單獨工作單元。原子性確保在十五中的所有操作要么都發(fā)生,要么都不發(fā)生。
一致性(Consistent):一旦一個事務(wù)結(jié)束了(不管成功失敗),系統(tǒng)所處的狀態(tài)和它的業(yè)務(wù)規(guī)則是一致的。就是說數(shù)據(jù)應(yīng)當(dāng)不會被破壞。
隔離性(Isolated):事務(wù)應(yīng)該允許多個用戶操作同一數(shù)據(jù),一個用戶的操作不會和其他用戶的操作相混淆。因此,事務(wù)必須是互相隔離的,防止并發(fā)讀寫同一數(shù)據(jù)的情況發(fā)生。
持久性(Durable):一旦事務(wù)完成,事務(wù)的結(jié)果應(yīng)該持久化,這樣不管什么樣的系統(tǒng)崩潰,他們都將幸免于難。
Spring對程序控制事務(wù)管理的支持和EJB的有很大不同。EJB的事務(wù)管理和JTA密不可分,和EJB不同的是,Spring使用了一種回調(diào)機(jī)制,把真實的事務(wù)實現(xiàn)從事務(wù)代碼中抽象出來。選擇程序控制事務(wù)管理還是聲明式事務(wù)管理,很大程度上是在細(xì)粒度控制與簡便操作之間做出決定。當(dāng)你在代碼中編寫事務(wù)時,你能精確控制事務(wù)的邊界,在你希望的地方精確的開始和結(jié)束。典型的情況下,你不需要程序控制事務(wù)所提供的細(xì)粒度控制,你會選擇在上下文定義文件中聲明你的事務(wù)。
Spring對聲明式事務(wù)管理的支持是通過它的AOP框架實現(xiàn)的。這樣做是非常自然的,因為事務(wù)是系統(tǒng)級的,凌駕于應(yīng)用的主要功能之上的。
在Spring里,事務(wù)屬性是對事務(wù)策略如何應(yīng)用到方法的描述。這個描述包括:傳播行為、隔離級別、只讀提示、事務(wù)超時間隔
傳播行為:
PROPAGATION_MANDATORY:表示該方法必須運(yùn)行在一個事務(wù)中。如果當(dāng)前事務(wù)不存在,將拋出一個異常。
PROPAGATION_NESTED:表示如果當(dāng)前已經(jīng)存在一個事務(wù),則該方法應(yīng)當(dāng)運(yùn)行在一個嵌套的事務(wù)中。被嵌套的事務(wù)可以從當(dāng)前事務(wù)中單獨的提交或回滾。如果當(dāng)前事務(wù)不存在,那么它看起來和PROPAGATION_REQUIRED沒有兩樣。
PROPAGATION_NEVER:表示當(dāng)前的方法不應(yīng)該運(yùn)行在一個事務(wù)上下文中。如果當(dāng)前存在一個事務(wù),則會拋出一個異常。
PROPAGATION_NOT_SUPPORTED:表示該方法不應(yīng)在事務(wù)中運(yùn)行。如果一個現(xiàn)有的事務(wù)正在運(yùn)行中,它將在該方法的運(yùn)行期間被掛起。
PROPAGATION_REQUIRED:表示當(dāng)前方法必須運(yùn)行在一個事務(wù)中。如果一個現(xiàn)有的事務(wù)正在運(yùn)行中,該方法將運(yùn)行在這個事務(wù)中。否則的話,要開始一個新的事務(wù)。
PROPAGATION_REQUIRES_NEW:表示當(dāng)前方法必須運(yùn)行在它自己的事務(wù)里。它將啟動一個新的事務(wù)。如果有事務(wù)運(yùn)行的話,將在這個方法運(yùn)行期間被掛起。
PROPAGATION_SUPPORTS:表示當(dāng)前方法不需要事務(wù)處理環(huán)境,但如果有一個事務(wù)已經(jīng)在運(yùn)行的話,這個方法也可以在這個事務(wù)里運(yùn)行。
傳播規(guī)則回答了一個問題:就是新的事務(wù)是否要被啟動或是被掛起,或者方法是否要在事務(wù)環(huán)境中運(yùn)行。
隔離級別:在一個典型的應(yīng)用中,多個事務(wù)并發(fā)運(yùn)行,經(jīng)常會操作同一個數(shù)據(jù)來完成它們的任務(wù)。并發(fā),雖然是必須的,但會導(dǎo)致下面問題:
1、臟讀:臟讀發(fā)生在一個事務(wù)讀取了被另一個事務(wù)改寫但還未提交的數(shù)據(jù)時。如果這些改變在稍后被回滾,那么第一個事務(wù)讀取的數(shù)據(jù)就是無效的。
2、不可重復(fù)讀:不可重復(fù)讀發(fā)生在一個事務(wù)執(zhí)行相同的查詢2次或2次以上,但每一次查詢結(jié)果都不同時。這通常是由于另一個并發(fā)事務(wù)在2次查詢之間更新了數(shù)據(jù)。
3、幻讀:幻讀和不可重復(fù)讀相似。當(dāng)一個事務(wù)讀取幾行紀(jì)錄后,另一個并發(fā)事務(wù)插入一些記錄,幻讀就發(fā)生了。隔離級別有如下幾個:
ISOLATION_DEFAULT:使用后端數(shù)據(jù)庫默認(rèn)的隔離級別
ISOLATION_READ_UNCOMMITTED:允許你讀取還未提交的改變了的數(shù)據(jù),可能導(dǎo)致臟讀、幻讀、不可重復(fù)讀
ISOLATION_READ_COMMITTED:允許在并發(fā)事務(wù)已經(jīng)提交后讀取。可防止臟讀,但幻讀和不可重復(fù)讀仍可能發(fā)生。
ISOLATION_REPEATABLE_READ:對相同字段的多次讀取的結(jié)果是一致的,除非數(shù)據(jù)被事務(wù)本身改變。可防止臟讀和不可重復(fù)讀,但幻讀仍可能發(fā)生。
ISOLATION_SERIALIZABLE:完全服從ACID的隔離級別,確保不發(fā)生臟讀、不可重復(fù)讀和幻讀。這在所有隔離級別中也是最慢的。
只讀:如果一個事務(wù)只對后端是據(jù)庫執(zhí)行讀操作,數(shù)據(jù)庫就可能利用事務(wù)只讀的特性,使用某些優(yōu)化措施。通過聲明一個事務(wù)為只讀,你就給了后端數(shù)據(jù)庫一個機(jī)會,來應(yīng)用那些它認(rèn)為合適的優(yōu)化措施。因為只讀的優(yōu)化措施是在事務(wù)啟動時由后端數(shù)據(jù)庫實施的,所以,只有將那些具有可能啟動新事務(wù)的傳播行為的方法的事務(wù)標(biāo)記成只讀才有意義(PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED) TransactionProxyFactoryBean參照一個方法的事務(wù)屬性,決定如何在那個方法上執(zhí)行事務(wù)策略。
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDatasource</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 這個對象有一個值為courseService的id.當(dāng)應(yīng)用從應(yīng)用上下文里請求一個courseService時,它將得到一個被
TransactionProxyFactoryBean包裹的實例。 -->
<bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 代理所實現(xiàn)的接口 -->
<property name="proxyInterfaces">
<list>
<value>
com.springinaction.training.service.CourseService
</value>
</list>
</property>
<!-- 被代理的對象 -->
<property name="target">
<ref bean="courseServiceTarget"/>
</property>
<!-- 事務(wù)管理器 -->
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<!-- 事務(wù)的屬性源 -->
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
<!-- 要知道盡管可以改變MatchAlwaysTransactionAttributeSource的事務(wù)屬性參數(shù),但它總是返回相同的事務(wù)屬性,而
不關(guān)心參與交易的哪一個方法。當(dāng)你有一個相對簡單的應(yīng)用,把同樣的事務(wù)策略應(yīng)用到所有方法都沒問題時,使用MatchAlwaysT
ransactionAttributeSource就相當(dāng)好。但是,在那些更為復(fù)雜的應(yīng)用中,你很可能需要對不同的方法應(yīng)用不同的事務(wù)策略。在那樣
情況下,你需要在應(yīng)用何種策略的問題上做更多精確的控制。 -->
<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute">
<ref bean="myTransactionAttribute"/>
</property>
</bean>
<!-- 定義事務(wù)策略 -->
<bean id="myTransactionAttribute" class="org.springframework.transaction.interceptor.DefaultTransactionAttribute">
<!-- 傳播行為 -->
<property name="propagationBehaviorName">
<value>PROPAGATION_REQUIRES_NEW</value>
</property>
<!-- 隔離級別 -->
<property name="isolationLevelName">
<value>ISOLATION_REPEATABLE_READ</value>
</property>
</bean>
</beans>
除了將transactionAttributeSource對象織入到TransactionProxyFactoryBean的transactionAttributeSource屬性中外,還有一種簡單的方法。發(fā)展到現(xiàn)在,TransactionProxyFactoryBean也有一個transactionAttributes屬性為transactionProperties.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDatasource</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 這個對象有一個值為courseService的id.當(dāng)應(yīng)用從應(yīng)用上下文里請求一個courseService時,它將得到一個被
TransactionProxyFactoryBean包裹的實例。 -->
<bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 代理所實現(xiàn)的接口 -->
<property name="proxyInterfaces">
<list>
<value>
com.springinaction.training.service.CourseService
</value>
</list>
</property>
<!-- 被代理的對象 -->
<property name="target">
<ref bean="courseServiceTarget"/>
</property>
<!-- 事務(wù)管理器 -->
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<!-- 事務(wù)的屬性源 -->
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
<!-- NameMatchTransactionAttributeSource的properties屬性把方法名映射到事務(wù)屬性描述器上。注意CourseException
用一個負(fù)號標(biāo)記。異常可以用負(fù)號或正號標(biāo)記,當(dāng)負(fù)號異常拋出時,將觸發(fā)回滾;相反的,正號異常表示事務(wù)仍可提交,即使這個異常拋出 -->
<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ,readOnly,
-CourseException
</prop>
<!-- 還可以使用通配符 -->
<prop key="get*">
PROPAGATION_SUPPORTS
</prop>
</props>
</property>
</bean>
</beans>
posted @
2009-11-22 11:43 王永慶 閱讀(258) |
評論 (0) |
編輯 收藏
HQL作為Hibernate的查詢語言,提供了ANSI SQL面向?qū)ο蟮姆庋b形式。
與Criteria和HQL互為補(bǔ)充,Hibernate也提供了對原生SQL以及存儲過程的支持,相對于JDBC的SQL操作,Hibernate提供了更為妥善的封裝。代碼如下:
package com.testproject.hibernate;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;


public class HibernateSqlQuery
{
Session session = null;

public void querySql()
{
String sql = "select {usr.*} from T_User usr";
List list = session.createSQLQuery(sql).addEntity("usr", TUser.class).list();
Iterator it = list.iterator();

while(it.hasNext())
{
TUser user = (TUser)it.next();
}
}

public void queryMappingSql()
{
Query query = session.getNamedQuery("queryUser");
query.setParameter("name","Erica");
Iterator it = query.list().iterator();

while(it.hasNext())
{
TUser user = (TUser)it.next();
}
}
}

<?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>
<class name="com.testproject.hibernate.TUser" table="T_USER">
<id name="id" column="id">
<generator class="native"></generator>
</id>
</class>
<sql-query name="queryUser">
<![CDATA[
select {usr.*} from T_User usr where name=:name
]]>
<return alias = "usr" class="com.testproject.hibernate.TUser"></return>
</sql-query>
<!-- 基于存儲過程查詢 sql-query節(jié)點的callable屬性設(shè)定為true,指明當(dāng)前查詢基于存儲過程定義-->
<sql-query name="getUsersByAge" callable="true">
<return alias="user" class="com.testproject.hibernate.TUser">
<return-property name="id" column="ID"></return-property>
<return-property name="name" column="NAME"></return-property>
<return-property name="age" column="AGE"></return-property>
</return>
{?=call getUsersByAge(?)}
</sql-query>
</hibernate-mapping>





與HQL相同,Native SQL也可以在實體映射文件中進(jìn)行配置:
posted @
2009-11-21 21:37 王永慶 閱讀(242) |
評論 (0) |
編輯 收藏
摘要: 實體Bean包含BMP和CMP兩種類型。對BMP實體Bean而言,開發(fā)者必須提供各自的數(shù)據(jù)訪問邏輯。為了實現(xiàn)BMP,通常會使用操作數(shù)據(jù)庫的API,比如JDBC.對于CMP實體Bean而言,EJB容器會自動實現(xiàn)數(shù)據(jù)訪問邏輯。這就是CMP的優(yōu)勢所在。通常,只有在應(yīng)用服務(wù)器提供的CMP和目標(biāo)RDBMS不能滿足性能要求時,才去考慮BMP.此時,開發(fā)者能夠細(xì)粒度調(diào)整BM...
閱讀全文
posted @
2009-11-21 12:32 王永慶 閱讀(215) |
評論 (0) |
編輯 收藏