小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JPA事務(wù)總結(jié)

 Gemmy 2010-04-13

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)最為典型。例如一個人去銀行取 款,他取款的錢此時大于銀行賬戶中的錢,此時交易失敗,所以取款不成功,事務(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>

除了在配置文件時指明了 事務(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

JTARESOURCE_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 Transaction API)是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ù)時, 需要注意以下幾個問題。

— 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的方法時,那么此時事務(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);

    }

}

此時在 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;

    }

}

此時 EntityManager對象是容器托管的,并且設(shè)置的事務(wù)類型為JPA。下面仔細(xì)分析一下,當(dāng)在一個EJB組件中調(diào)用另外一個EJB組件時,事務(wù)的傳 播與持久化上下文環(huán)境的關(guān)系。

— 當(dāng)客戶端調(diào)用addCustomer方法時,此時容器自動關(guān)聯(lián)一個JTA的事務(wù),一個事務(wù)開始,這里將該事務(wù)記為事務(wù)A。

— 當(dāng)調(diào)用persist方法持久化客戶時,EntityManager對象發(fā)現(xiàn)當(dāng)前有一個JTA的事務(wù)A,則此時將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方法時,再次調(diào)用persist方法持久化日志時,由于此時EntityManager對象的事務(wù)是附加到JTA事務(wù)A中的,所 以仍與之前調(diào)用的persist方法時所在的持久化上下文相同,所以,可以直接調(diào)用持久化客戶后的customer.getId(),來獲得持久化客戶的 Id值。雖然在一個EJB組件中調(diào)用了另外一個EJB組件的方法,但兩次調(diào)用的persist方法所在的持久化上下文是相同的。

— recordLog方法結(jié)束,又回到addCustomer方法中,此時事務(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ù)時需要注意以下幾個問題。

— 在J2SE環(huán)境中,只能使用RESOURCE_LOCAL管理EntityManager事務(wù),并且EntityManager對象是以應(yīng)用托管方式獲得 的。

— 代碼中使用RESOURCE_LOCAL管理事務(wù)時,要通過調(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ù)據(jù)庫支持事務(wù)。例如使用MySQL時,需要設(shè)置數(shù)據(jù)庫的引擎類型為 “InnoDB”,而“MyISAM”類型是不支持事務(wù)的。

— 在代碼中,entityManager.getTransaction()方法獲得本地事務(wù)EntityTransaction對象,然后通過該對象提供 的方法來控制本地的事務(wù)。有關(guān)EntityTransaction的API將在下一節(jié)講述。

— 控制本地事務(wù)時,開始一個新事務(wù),使用begin()方法;事務(wù)完成后,使用commit()方法提交??刂剖聞?wù)時,并沒有調(diào)用rollback()方法 回滾,這是因?yàn)樵谑聞?wù)開始后,一旦有異常拋出,EntityTransaction對象將自動回滾,所以并不需要顯式地調(diào)用rollback()方法回 滾。

11.4.4  EntityTransaction API

下面來看本地事務(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ù):無。

異常信息:如果此時事務(wù)處于激活狀態(tài),即isActive()為true,將拋出 IllegalStateException異常。

返回值:無返回值。

— public void commit()

作用:提交事務(wù),事務(wù)所涉及的數(shù)據(jù)的更新將全部同步到數(shù)據(jù)庫中。

方法參數(shù):無。

異常信息:如果此時事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出 IllegalState Exception異常;如果此時提交不成功,則拋出RollbackException異常。

返回值:無返回值。

— public void rollback()

作用:事務(wù)回滾。

方法參數(shù):無。

異常信息:如果此時事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出 IllegalState Exception異常;如果此時回滾失敗,則拋出PersistenceException異常。

返回值:無返回值。

— public void setRollbackOnly()

作用:設(shè)置當(dāng)前的事務(wù)只能是回滾狀態(tài)。

方法參數(shù):無。

異常信息:如果此時事務(wù)處于未激活狀態(tài),即isActive()為false,將拋出 IllegalState Exception異常。

返回值:無返回值。

— public boolean getRollbackOnly()

作用:獲得當(dāng)前事務(wù)的回滾狀態(tài)。

方法參數(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)閉,所以此時,只需要控制EntityManager的打開 和關(guān)閉。當(dāng)客戶端每次調(diào)用Bean中的方法時,都首先創(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, OrderEO order) {

        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中的管理方式不同,此時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ù)的方法時,需要使用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, OrderEO order) {

        /**

        *EntityManager 對象的作用范圍是這個Bean的生命周期

        *所以,每次使用時要合并到上一次的事務(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此時是有狀態(tài)的Bean,所以當(dāng)客戶端調(diào)用任何方法時,都處在同一個持 久化上下文中。所以每次并不需要調(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, OrderEO order) {

        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ù)時要使用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, OrderEO order) {

        em.getTransaction().begin();

        customer.getOrders().add(order);

        em.getTransaction().commit();

    }

    public void destroy(){

        em.close();

        emf.close();

    }

}


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多