在ejb組件設計中,組件行為有時需要具備事務特征,即使用事務保證組件行為的完整性,使組件要么執行成功,要么回到起點.等價沒有執行!
討論事務時要明確兩個概念:
事務范圍
算法的可恢復性與事務性:如果事務中的算法動作結果受事務提交或者回滾影響,則該算法具有事務可恢復性,否則就不具備事務可恢復性.
事務在本質上就是一個管理系列算法動作一致性的對象!ejb提供了兩種事務類型:聲明性和程序性事務
聲明性事務:由ejb容器負責事務對象的 生成,管理,銷毀;具體算法在事務上的注冊,事務的提交和回滾等
主要介紹聲明性的事務:
ejb容器為其中的
所有的ejb組件提供了一種默認的事務模式:Requires
在該模式下面,組件中的方法如果在事務環境下被調用(即客戶端調用了該組件的方法),則方法中的邏輯會被添加到客戶端的事務環境中,和客戶端的程序使用相同的事務控制對象.如果不在事務環境中調用(在客戶端沒有調用該組件中的方法),ejb容器就創建新的事務對象,管理該方法中的所有邏輯.
例如:
ejb組件:
@Statefull
public class personmanager inplements IPersonAdmin{
@PersistenceContext(unitName="mydb")
private EntityManager manager;
@EJB(mappedName="MySession/remote")
private IPersonAdmin mytools;
public List<person> QueryAll(){
....
}
public void createPerson(Person p){
Person pobj=new Person();
pobj.setName("ziaoxioa");
#1 manager.persist(pobj);
#2 mytools.createPerson(p);
#3 manager.persist(null);
}
客戶代碼:
...
myinf.createPerson(p);
...
默認情況下,ejb讀物起會為ejb組件中的所有方法配置一中requires型的事務服務.在這種事務模式下面,如果方法被在事務環境下調用,方法就使用客戶端事務對象和事務環境ruguo不在事務環境中被調用,則ejb容器就會創建新的事務對象和環境來負責管理該方法的邏輯完整性!由于上面的#3錯誤,所以數據庫中不會添加任何記錄!
ejb容器為ejb組件添加的默認的事務策略能夠滿足多數情況下的算法要求,特殊情況下,可以通過@TransactionAttribute和<container-transaction>標記修改組件的默認事務策略!如下:
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>MySession</ejb-name>
<method-name>createPerson</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
@TransactionAttribute(REQUIRES_NEW)
public void createPerson(Person p){
manager.persist(p);
}
這樣MySession中的createPerson方法事務修改成了RequiesNew模式,在這種模式下,ejb容器不論客戶端是否具有事務特征,為createPerson創建一個新的事務對象,此時兩個createPerson在完全不同的事務對象控制下,所以#2可以提交到數據庫中,#1,#3則回滾
聲明性事務模式:
Required |
ejb容器為ejb組件方法提供的默認事務模式,在這種模式下,如果調用程序具備自身的事務對象,則組件方法就和客戶程序使用相同的事務對象,否則ejb容器就會創建新的事務對象來管理組件方法邏輯 |
Supports |
在這種模式下,如果調用程序具備事務特征,則組件方法就會調用調用程序事務對象管理自身邏輯,如果調用程序不包含任何的事務對象,則組件方法也處于無事務管理狀態 |
NotSupported |
這種模式下,組件方法不支持事務,同時也會忽略掉調用程序中的事務對象,組件方法中的邏輯不受客戶程序事務的提交或回滾的影響 |
RequiresNew |
在這種模式下,忽略調用程序具備的事務特征,ejb容器會新創建一個新的事務對象管理組件方法邏輯 |
Mandatory |
ejb容器不會為該方法創建新的事務管理對象。該組件方法的調用程序必須提供事務對象,處于事務環境中,否則程序將產生異常javax.ejb.EJBTransactionRequiredException
|
Never |
這種模式下,該方法不會被ejb容器提供事務對象服務,并且調用程序也不能處于事務環境中,否則將產生EJBException異常
|
下面的程序首先清楚組件上的默認事務模式,然后在為方法設定具體事務屬性:
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>MySession</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>MySession</ejb-name>
<method-name>createPerson</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
聲明性事務的控制:
@Stateless
/*10*/public class PersonManager implements IPersonAdmin
/*11*/{
/*12*/ @Resource
/*13*/ private EJBContext ctx;
/*14*/ @PersistenceContext(unitName="mydb")
/*15*/ private EntityManager manager;
/*16*/ @EJB(mappedName="MySession/remote")
/*17*/ private IPersonAdmin mytools;
/*18*/ public List<Person> QueryAll()
/*19*/ {
/*20*/ Query q=manager.createQuery("from Person c");
/*21*/ List results=q.getResultList();
/*22*/ List<Person> result=(List<Person>)results;
/*23*/ return result;
/*24*/ }
/*25*/ public void createPerson(Person p)
/*26*/ {
/*27*/ Person pobj=new Person();
/*28*/ pobj.setName("zhanghao");
/*29*/ pobj.setAge(new Integer(32));
/*30*/ pobj.setSex("male");
/*31*/ manager.persist(pobj);
/*32*/ boolean result=ctx.getRollbackOnly();
/*33*/ if(!result)
/*34*/ {
/*35*/ ctx.setRollbackOnly();
/*36*/ }
/*37*/ }
/*38*/}
該方法使用gejb容器提供的默認的事務模式,事務會在方法結束時自動提交。
getRollbackOnly()返回房前事務的狀態,true表示已經回滾,false表示沒有回滾。