国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
JPA事務(wù)總結(jié)
原文摘自:JPA數(shù)據(jù)庫持久層開發(fā)實(shí)踐
作者:馮曼菲
事務(wù)管理是JPA中另一項(xiàng)重要的內(nèi)容,了解了JPA中的事務(wù)管理,能夠進(jìn)一步掌握J(rèn)PA的使用。事務(wù)管理是對一系列操作的管理,它最終只有兩個結(jié)果,要么成功,要么失敗。一旦失敗,所有的操作將回滾到初始狀態(tài)。一旦成功,才最終提交,最終持久化。事務(wù)管理對銀行系統(tǒng)最為典型。例如一個人去銀行取款,他取款的錢此時(shí)大于銀行賬戶中的錢,此時(shí)交易失敗,所以取款不成功,事務(wù)回滾到操作前的狀態(tài)。
在JPA中,對于實(shí)體的“CRUD”基本操作,其中涉及事務(wù)的是“C”、“U”和“D”,即“新建”、“更新”和“刪除”,因?yàn)檫@些操作都會影響數(shù)據(jù)庫中的數(shù)據(jù)變化,所以必須使用事務(wù)保證其一致性;對于“R”查詢,只是查詢數(shù)據(jù),沒有對數(shù)據(jù)產(chǎn)生變化,所以并不需要控制事務(wù)。
所以,一說到事務(wù),讀者首先應(yīng)確定所使用的操作是否需要關(guān)聯(lián)事務(wù),先要界定事務(wù)所有效使用的范圍。
11.4.1  事務(wù)與EntityManager
EntityManager對象的事務(wù)管理方式有兩種,分別為JTA和RESOURCE_LOCAL,即Java Transaction API方法和本地的事務(wù)管理。
JPA中的事務(wù)類型通過persistence.xml文件中的“transaction-type”元素配置。例如,配置事務(wù)為JTA方式的代碼如下所示。
<persistence>
<persistence-unit name="demo"transaction-type="JTA">
//其他配置省略
</persistence-unit>
</persistence>
如果使用RESOURCE_LOCAL管理事務(wù),則配置代碼如下所示。
<persistence>
<persistence-unit name="demo"transaction-type="RESOURCE_LOCAL">
//其他配置省略
</persistence-unit>
</persistence>
除了在配置文件時(shí)指明了事務(wù)的類型,不同的事務(wù)類型,不同類型的EntityManager對象,在代碼中控制事務(wù)也是不同的。表11-2為不同的運(yùn)行環(huán)境、不同的EntityManager對象所支持的事務(wù)類型。
表11-2  事務(wù)類型與EntityManager
運(yùn)行環(huán)境
類型
J2EE環(huán) 境
J2SE環(huán) 境
EJB容 器
Web容 器
應(yīng)用托管的EntityManager
JTA,RESOURCE_LOCAL
JTA,RESOURCE_LOCAL
RESOURCE_LOCAL
容器托管的EntityManager
JTA
不支持
不支持
從表11-2中可以看出,對于不同的EntityManager類型與所運(yùn)行的環(huán)境,所支持的事務(wù)類型是不一樣的。
其中兩種情況下最為簡單,一種是容器托管的EntityManager只能運(yùn)行在EJB容器中,只能采用JTA的方式管理事務(wù);另一種是J2SE環(huán)境下,只能使用應(yīng)用托管的EntityManager并且只能采用RESOURCE_LOCAL的方式管理事務(wù)。本節(jié)的事務(wù)只針對這兩種情況講述,而對于應(yīng)用托管的EntityManager在EJB容器和Web容器中由于都可以選擇不同的事務(wù)管理方式,情況比較復(fù)雜,所以將在第11.5節(jié)中詳細(xì)講述。
11.4.2  JTA管理事務(wù)
JTA事務(wù)(Java TransactionAPI)是J2EE規(guī)范中有關(guān)事務(wù)的標(biāo)準(zhǔn)。它是容器級別的事務(wù),只能運(yùn)行在J2EE服務(wù)器中。它的最大優(yōu)勢是可以支持分布式的事務(wù),如果系統(tǒng)采用的是分布式的數(shù)據(jù)庫,那么只能選擇JTA管理EntityManager事務(wù)。
使用JTA管理EntityManager事務(wù)時(shí),需要注意以下幾個問題。
—JTA事務(wù)只能運(yùn)行在J2EE的環(huán)境中,即EJB容器中和Web容器中;而在J2SE環(huán)境中只能使用RESOURCE_LOCAL管理事務(wù)。
—容器托管的EntityManager對象只能采用JTA的事務(wù),而不能采用RESOURCE_LOCAL事務(wù)。
在第11.3節(jié)中,已經(jīng)簡單了解了一些JTA事務(wù)與EntityManager之間的關(guān)系,但當(dāng)Bean的方法中又調(diào)用了另一個Bean的方法時(shí),那么此時(shí)事務(wù)傳播(Propagation)是如何進(jìn)行的?下面就深入了解事務(wù)的傳播與持久化上下文的關(guān)系。
有這樣一個記錄日志的會話Bean,它負(fù)責(zé)記錄相關(guān)的日志信息等,它有一個記錄日志的方法recordLog,代碼如下所示。
@Stateless
public class LogService implements ILogService {
@PersistenceContext(unitName = "jpaUnit")
private EntityManager entityManager;
/**記錄日志*/
public void recordLog(Integer id, String reason) {
LogEO log = new LogEO();
log.setId(id);
log.setReason(reason);
entityManager.persist(log);
}
}
此時(shí)在CustomerService的會話Bean中,addCustomer方法中需要新建客戶后,再調(diào)用日志組件來記錄日志信息,代碼如下所示。
@Stateless
public class CustomerService implements ICustomerService {
@PersistenceContext(unitName = "jpaUnit")
private EntityManager entityManager;
@EJB
private ILogService logService ;
public CustomerEO addCustomer(CustomerEO customer) {
entityManager.persist(customer);
logService.recordLog(customer.getId(),"新建Customer");
return customer;
}
}
此時(shí)EntityManager對象是容器托管的,并且設(shè)置的事務(wù)類型為JPA。下面仔細(xì)分析一下,當(dāng)在一個EJB組件中調(diào)用另外一個EJB組件時(shí),事務(wù)的傳播與持久化上下文環(huán)境的關(guān)系。
—當(dāng)客戶端調(diào)用addCustomer方法時(shí),此時(shí)容器自動關(guān)聯(lián)一個JTA的事務(wù),一個事務(wù)開始,這里將該事務(wù)記為事務(wù)A。
—當(dāng)調(diào)用persist方法持久化客戶時(shí),EntityManager對象發(fā)現(xiàn)當(dāng)前有一個JTA的事務(wù)A,則此時(shí)將EntityManager對象的事務(wù)附加到JTA的事務(wù)A中,并且創(chuàng)建了一個新的持久化上下文。
—調(diào)用日志組件的recordLog方法,容器發(fā)現(xiàn)調(diào)用了另外一個EJB的方法,所以首先檢查當(dāng)前是否存在事務(wù),由于當(dāng)前狀態(tài)下存在事務(wù)A,所以將recordLog方法的事務(wù)附加到事務(wù)A中(由于默認(rèn)情況下,CustomerService的事務(wù)類型是REQUIRED)。
—當(dāng)進(jìn)入recordLog方法時(shí),再次調(diào)用persist方法持久化日志時(shí),由于此時(shí)EntityManager對象的事務(wù)是附加到JTA事務(wù)A中的,所以仍與之前調(diào)用的persist方法時(shí)所在的持久化上下文相同,所以,可以直接調(diào)用持久化客戶后的customer.getId(),來獲得持久化客戶的Id值。雖然在一個EJB組件中調(diào)用了另外一個EJB組件的方法,但兩次調(diào)用的persist方法所在的持久化上下文是相同的。
—recordLog方法結(jié)束,又回到addCustomer方法中,此時(shí)事務(wù)A提交,一個持久化上下文也就隨之結(jié)束了。
11.4.3  RESOURCE_LOCAL管理事務(wù)
RESOURCE_LOCAL事務(wù)數(shù)據(jù)庫本地的事務(wù)。它是數(shù)據(jù)庫級別的事務(wù),只能針對一種數(shù)據(jù)庫,不支持分布式的事務(wù)。對于中小型的應(yīng)用,可以采用RESOURCE_LOCAL管理EntityManager事務(wù)。
使用RESOURCE_LOCAL管理EntityManager事務(wù)時(shí)需要注意以下幾個問題。
—在J2SE環(huán)境中,只能使用RESOURCE_LOCAL管理EntityManager事務(wù),并且EntityManager對象是以應(yīng)用托管方式獲得的。
—代碼中使用RESOURCE_LOCAL管理事務(wù)時(shí),要通過調(diào)用EntityManager的getTransac-tion()方法獲得本地事務(wù)對象。
例如,在J2SE環(huán)境中,使用RESOURCE_LOCAL管理EntityManager事務(wù)的代碼如下所示。
public class CustomerClient {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("jpaUnit");
EntityManager entityManager =emf.createEntityManager();
try {
/** 事務(wù)開始 */
entityManager.getTransaction().begin();
CustomerEO customer = new CustomerEO();
customer.setName("Janet");
customer.setEmail("janetvsfei@yahoo.com.cn");
customer.setAsset(100000.00);
/** 事務(wù)提交 */
entityManager.getTransaction().commit();
} finally {
entityManager.close();
emf.close();
}
}
}
★ 提示 ★
采用RESOURCE_LOCAL管理事務(wù)時(shí),要保證數(shù)據(jù)庫支持事務(wù)。例如使用MySQL時(shí),需要設(shè)置數(shù)據(jù)庫的引擎類型為“InnoDB”,而“MyISAM”類型是不支持事務(wù)的。
—在代碼中,entityManager.getTransaction()方法獲得本地事務(wù)EntityTransaction對象,然后通過該對象提供的方法來控制本地的事務(wù)。有關(guān)EntityTransaction的API將在下一節(jié)講述。
—控制本地事務(wù)時(shí),開始一個新事務(wù),使用begin()方法;事務(wù)完成后,使用commit()方法提交??刂剖聞?wù)時(shí),并沒有調(diào)用rollback()方法回滾,這是因?yàn)樵谑聞?wù)開始后,一旦有異常拋出,EntityTransaction對象將自動回滾,所以并不需要顯式地調(diào)用rollback()方法回滾。
11.4.4  EntityTransactionAPI
下面來看本地事務(wù)EntityTransaction中所定義的方法EntityTransaction API,以及它們的作用,如下所示。
EntityTransaction API
package javax.persistence;
public interface EntityTransaction {
public void begin();
public void commit();
public void rollback();
public void setRollbackOnly();
public boolean getRollbackOnly();
public boolean isActive();
}
下面具體來看各個方法所表示的意義,每個方法都從作用、方法參數(shù)、異常信息,以及返回值這幾個方面來講述。
— public void begin()
作用:聲明事務(wù)開始。
方法參數(shù):無。
異常信息:如果此時(shí)事務(wù)處于激活狀態(tài),即isActive()為true,將拋出IllegalStateException異常。
返回值:無返回值。
— public void commit()
作用:提交事務(wù),事務(wù)所涉及的數(shù)據(jù)的更新將全部同步到數(shù)據(jù)庫中。
方法參數(shù):無。
異常信息:如果此時(shí)事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出IllegalState Exception異常;如果此時(shí)提交不成功,則拋出RollbackException異常。
返回值:無返回值。
— public void rollback()
作用:事務(wù)回滾。
方法參數(shù):無。
異常信息:如果此時(shí)事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出IllegalState Exception異常;如果此時(shí)回滾失敗,則拋出PersistenceException異常。
返回值:無返回值。
— public void setRollbackOnly()
作用:設(shè)置當(dāng)前的事務(wù)只能是回滾狀態(tài)。
方法參數(shù):無。
異常信息:如果此時(shí)事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出IllegalState Exception異常。
返回值:無返回值。
— public boolean getRollbackOnly()
作用:獲得當(dāng)前事務(wù)的回滾狀態(tài)。
方法參數(shù):無。
異常信息:如果此時(shí)事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出IllegalState Exception異常。
返回值:true表示只能回滾狀態(tài)。
— public boolean isActive ()
作用:判斷當(dāng)前事務(wù)是否處于激活狀態(tài)。
方法參數(shù):無。
異常信息:如果發(fā)生了未知的異常,將拋出PersistenceException異常。
返回值:true表示當(dāng)前事務(wù)處于激活狀態(tài),false表示當(dāng)前事務(wù)未處于激活狀態(tài)。
11.5 應(yīng)用托管的EntityManager的持久化上下文
通過表11-2所總結(jié)的各種情況,應(yīng)用托管EntityManager對象在EJB容器中和Web容器中,可選擇的事務(wù)類型比較復(fù)雜,既可以支持JTA,又可以支持RESOURCE_LOCAL。下面講述在這兩種情況下,如何控制事務(wù)。
11.5.1 無狀態(tài)的會話Bean與JTA事務(wù)(事務(wù)范圍)
在會話Bean里以注入的方式獲得EntityManagerFactory對象,不需要負(fù)責(zé)它的關(guān)閉,所以此時(shí),只需要控制EntityManager的打開和關(guān)閉。當(dāng)客戶端每次調(diào)用Bean中的方法時(shí),都首先創(chuàng)建EntityManager對象,然后在方法結(jié)束前關(guān)閉EntityManager對象。EntityManager對象的事務(wù)使用的是容器自動管理的事務(wù)JTA。
代碼如下所示。
@Stateless
public class CustomerService implements ICustomerService {
@PersistenceUnit(unitName="jpaUnit")
private EntityManagerFactory emf;
public CustomerEO findCustomerById(Integer customerId){
EntityManager em = emf.createEntityManager();
CustomerEO customer = em.find(CustomerEO.class,customerId);
em.close();
return customer;
}
public void placeOrder(Integer customerId, OrderEOorder) {
EntityManager em = emf.createEntityManager();
CustomerEO customer = em.find(CustomerEO.class,customerId);
customer.getOrders().add(order);
em.merge(customer);
em.close();
}
}
11.5.2 無狀態(tài)的會話Bean與JTA事務(wù)(擴(kuò)展范圍)
與上個會話Bean中的管理方式不同,此時(shí)EntityManager對象為Bean的屬性,當(dāng)Bean初始化后,也就是標(biāo)注@PostConstruct方法后,創(chuàng)建EntityManager對象;當(dāng)Bean銷毀前,也就是標(biāo)注@PreDestroy方法后,關(guān)閉EntityManager對象,所以EntityManager對象是整個的Bean的聲明周期中。當(dāng)客戶端調(diào)用需要關(guān)聯(lián)事務(wù)的方法時(shí),需要使用joinTransaction()方法合并到上一次的事務(wù)中。
代碼如下所示。
@Stateless
public class CustomerService implements ICustomerService {
@PersistenceUnit(unitName="jpaUnit")
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct
public void init (){
em = emf.createEntityManager();
}
public CustomerEO findCustomerById(Integer customerId){
/**查詢不需要關(guān)聯(lián)事務(wù)*/
CustomerEO customer = em.find(CustomerEO.class,customerId);
em.clear();
return customer;
}
public void placeOrder(Integer customerId, OrderEOorder) {
/**
*EntityManager 對象的作用范圍是這個Bean的生命周期
*所以,每次使用時(shí)要合并到上一次的事務(wù)中
*/
em.joinTransaction();
CustomerEO customer = em.find(CustomerEO.class,customerId);
customer.getOrders().add(order);
em.merge(customer);
/**
* 手動脫離當(dāng)前事務(wù)和持久化上下文
*/
em.flush();
em.clear();
}
@PreDestroy
public void destroy(){
em.close();
}
}
11.5.3  有狀態(tài)的會話Bean與JTA事務(wù)
同樣是EntityManager對象在整個的Bean的聲明周期中,但由于會話Bean此時(shí)是有狀態(tài)的Bean,所以當(dāng)客戶端調(diào)用任何方法時(shí),都處在同一個持久化上下文中。所以每次并不需要調(diào)用clear()方法來手動地脫離當(dāng)前的上下文,但每次客戶端的調(diào)用仍需要使用joinTransaction()方法合并到上一次的事務(wù)中。
代碼如下所示。
@Stateful
public class CustomerService implements ICustomerService {
@PersistenceUnit(unitName="jpaUnit")
private EntityManagerFactory emf;
private EntityManager em;
private  CustomerEO customer ;
@PostConstruct
public void init (){
em = emf.createEntityManager();
}
public CustomerEO findCustomerById(Integer customerId){
customer = em.find(CustomerEO.class, customerId);
return customer;
}
public void placeOrder(Integer customerId, OrderEOorder) {
em.joinTransaction();
customer.getOrders().add(order);
}
@Remove
public void destroy(){
em.close();
}
}
11.5.4  RESOURCE_LOCAL事務(wù)
前面三節(jié)的例子講述的是JTA事務(wù),當(dāng)在J2SE環(huán)境中,必須采用RESOURCE_LOCAL事務(wù),而且需要手動創(chuàng)建和關(guān)閉EntityManagerFactory、EntityManager對象。關(guān)聯(lián)事務(wù)時(shí)要使用EntityManager對象的getTransaction().begin()和getTransaction().commit()方法。
代碼如下所示。
public class CustomerService {
private EntityManagerFactory emf;
private EntityManager em;
public CustomerService (){
emf =Persistence.createEntityManagerFactory("jpaUnit");
em = emf.createEntityManager();
}
private  CustomerEO customer ;
public CustomerEO findCustomerById(Integer customerId){
customer = em.find(CustomerEO.class, customerId);
return customer;
}
public void placeOrder(Integer customerId, OrderEOorder) {
em.getTransaction().begin();
customer.getOrders().add(order);
em.getTransaction().commit();
}
public void destroy(){
em.close();
emf.close();
}
}
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JPA EntityManager 詳解
Spring 與 EJB 比較
JPA 一對一關(guān)聯(lián)
jpa多對多映射案例
JPA入門例子(采用JPA的hibernate實(shí)現(xiàn)版本)
操作EntityManager
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服