`
zzc1684
  • 浏览: 1233200 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

JPA事务总结

    博客分类:
  • JPA
阅读更多

事务管理是JPA中另一项重要的内容,了解了JPA中的事务管理,能够进一步掌握JPA的使用。事务管理是对一系列操作的管理,它最终只有两个结 果,要么成功,要么失败。一旦失败,所有的操作将回滚到初始状态。一旦成功,才最终提交,最终持久化。事务管理对银行系统最为典型。例如一个人去银行取 款,他取款的钱此时大于银行账户中的钱,此时交易失败,所以取款不成功,事务回滚到操作前的状态。

在JPA中,对于实体的“CRUD”基本操作,其中 涉及事务的是“C”、“U”和“D”,即“新建”、“更新”和“删除”,因为这些操作都会影响数据库中的数据变化,所以必须使用事务保证其一致性;对于 “R”查询,只是查询数据,没有对数据产生变化,所以并不需要控制事务。

所以,一说到事务,读者首先应确定所使用的操作是否 需要关联事务,先要界定事务所有效使用的范围。

11.4.1  事务与EntityManager

EntityManager对象的事务管理方式有两 种,分别为JTA和RESOURCE_LOCAL,即Java Transaction API方法和本地的事务管理。

JPA中的事务类 型通过persistence.xml文件中的“transaction-type”元素配置。例如,配置事务为JTA方式的代码如下所示。

<persistence>

    <persistence-unit name="demo" transaction-type="JTA">

        //其他配置省略

    </persistence-unit>

</persistence>

如果使用 RESOURCE_LOCAL管理事务,则配置代码如下所示。

<persistence>

    <persistence-unit name="demo" transaction-type="RESOURCE_LOCAL">

        //其他配置省略

    </persistence-unit>

</persistence>

除了在配置文件时指明了 事务的类型,不同的事务类型,不同类型的EntityManager对象,在代码中控制事务也是不同的。表11-2为不同的运行环境、不同的 EntityManager对象所支持的事务类型。

表11-2  事务类型与EntityManager

运行环境

类型

J2EE环 境

J2SE环 境

EJB容 器

Web容 器

应用托管的EntityManager

JTARESOURCE_LOCAL

JTARESOURCE_LOCAL

RESOURCE_LOCAL

容器托管的EntityManager

JTA

不支持

不支持

从表11-2中可以看 出,对于不同的EntityManager类型与所运行的环境,所支持的事务类型是不一样的。

其中两种情况下最为简单,一种是容器托管的 EntityManager只能运行在EJB容器中,只能采用JTA的方式管理事务;另一种是J2SE环境下,只能使用应用托管的 EntityManager并且只能采用RESOURCE_LOCAL的方式管理事务。本节的事务只针对这两种情况讲述,而对于应用托管的 EntityManager在EJB容器和Web容器中由于都可以选择不同的事务管理方式,情况比较复杂,所以将在第11.5节中详细讲述。

11.4.2  JTA管理事务

JTA事务(Java Transaction API)是J2EE规范中有关事务的标准。它是容器级别的事务,只能运行在J2EE服务器中。它的最大优势是可以支持分布式的事务,如果系统采用的是分布 式的数据库,那么只能选择JTA管理EntityManager事务。

使用JTA管理EntityManager事务时, 需要注意以下几个问题。

— JTA事务只能运行在J2EE的环境中,即EJB容器中和Web容器中;而在J2SE环境中只能使用RESOURCE_LOCAL管理事务。

— 容器托管的EntityManager对象只能采用JTA的事务,而不能采用RESOURCE_LOCAL事务。

在第11.3节中,已经简单了解了一些JTA事务与 EntityManager之间的关系,但当Bean的方法中又调用了另一个Bean的方法时,那么此时事务传播(Propagation)是如何进行 的?下面就深入了解事务的传播与持久化上下文的关系。

有这样一个记录日 志的会话Bean,它负责记录相关的日志信息等,它有一个记录日志的方法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方法中需要新建客户后,再调用日志组件来记录日志信息,代码如下所示。

@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对象是容器托管的,并且设置的事务类型为JPA。下面仔细分析一下,当在一个EJB组件中调用另外一个EJB组件时,事务的传 播与持久化上下文环境的关系。

— 当客户端调用addCustomer方法时,此时容器自动关联一个JTA的事务,一个事务开始,这里将该事务记为事务A。

— 当调用persist方法持久化客户时,EntityManager对象发现当前有一个JTA的事务A,则此时将EntityManager对象的事务附 加到JTA的事务A中,并且创建了一个新的持久化上下文。

— 调用日志组件的recordLog方法,容器发现调用了另外一个EJB的方法,所以首先检查当前是否存在事务,由于当前状态下存在事务A,所以将 recordLog方法的事务附加到事务A中(由于默认情况下,CustomerService的事务类型是REQUIRED)。

— 当进入recordLog方法时,再次调用persist方法持久化日志时,由于此时EntityManager对象的事务是附加到JTA事务A中的,所 以仍与之前调用的persist方法时所在的持久化上下文相同,所以,可以直接调用持久化客户后的customer.getId(),来获得持久化客户的 Id值。虽然在一个EJB组件中调用了另外一个EJB组件的方法,但两次调用的persist方法所在的持久化上下文是相同的。

— recordLog方法结束,又回到addCustomer方法中,此时事务A提交,一个持久化上下文也就随之结束了。

11.4.3  RESOURCE_LOCAL管理事务

RESOURCE_LOCAL 事务数据库本地的事务。它是数据库级别的事务,只能针对一种数据库,不支持分布式的事务。对于中小型的应用,可以采用RESOURCE_LOCAL管理 EntityManager事务。

使用RESOURCE_LOCAL管理 EntityManager事务时需要注意以下几个问题。

— 在J2SE环境中,只能使用RESOURCE_LOCAL管理EntityManager事务,并且EntityManager对象是以应用托管方式获得 的。

— 代码中使用RESOURCE_LOCAL管理事务时,要通过调用EntityManager的getTransac- tion()方法获得本地事务对象。

例如,在J2SE环境中,使用RESOURCE_LOCAL管理EntityManager事务的代码如下所 示。

public class CustomerClient {

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence

                .createEntityManagerFactory("jpaUnit");

        EntityManager entityManager = emf.createEntityManager();

        try {

            /** 事务开始 */

            entityManager.getTransaction().begin();

            CustomerEO customer = new CustomerEO();

            customer.setName("Janet");

            customer.setEmail("janetvsfei@yahoo.com.cn");

            customer.setAsset(100000.00);

            /** 事务提交 */

            entityManager.getTransaction().commit();

        } finally {

            entityManager.close();

            emf.close();

        }

    }

}

★ 提示 ★

采用RESOURCE_LOCAL管理事务时,要保证数据库支持事务。例如使用MySQL时,需要设置数据库的引擎类型为 “InnoDB”,而“MyISAM”类型是不支持事务的。

— 在代码中,entityManager.getTransaction()方法获得本地事务EntityTransaction对象,然后通过该对象提供 的方法来控制本地的事务。有关EntityTransaction的API将在下一节讲述。

— 控制本地事务时,开始一个新事务,使用begin()方法;事务完成后,使用commit()方法提交。控制事务时,并没有调用rollback()方法 回滚,这是因为在事务开始后,一旦有异常抛出,EntityTransaction对象将自动回滚,所以并不需要显式地调用rollback()方法回 滚。

11.4.4  EntityTransaction API

下面来看本地事务 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();

}

下面具体来看各个方法所 表示的意义,每个方法都从作用、方法参数、异常信息,以及返回值这几个方面来讲述。

— public void begin()

作用:声明事务开始。

方法参数:无。

异常信息:如果此时事务处于激活状态,即isActive()为true,将抛出 IllegalStateException异常。

返回值:无返回值。

— public void commit()

作用:提交事务,事务所涉及的数据的更新将全部同步到数据库中。

方法参数:无。

异常信息:如果此时事务处于未激活状态,即isActive()为false,将抛出 IllegalState Exception异常;如果此时提交不成功,则抛出RollbackException异常。

返回值:无返回值。

— public void rollback()

作用:事务回滚。

方法参数:无。

异常信息:如果此时事务处于未激活状态,即isActive()为false,将抛出 IllegalState Exception异常;如果此时回滚失败,则抛出PersistenceException异常。

返回值:无返回值。

— public void setRollbackOnly()

作用:设置当前的事务只能是回滚状态。

方法参数:无。

异常信息:如果此时事务处于未激活状态,即isActive()为false,将抛出 IllegalState Exception异常。

返回值:无返回值。

— public boolean getRollbackOnly()

作用:获得当前事务的回滚状态。

方法参数:无。

异常信息:如果此时事务处于未激活状态,即isActive()为false,将抛出 IllegalState Exception异常。

返回值:true表示只能回滚状态。

— public boolean isActive ()

作用:判断当前事务是否处于激活状态。

方法参数:无。

异常信息:如果发生了未知的异常,将抛出PersistenceException异常。

返回值:true表示当前事务处于激活状态,false表示当前事务未处于激活状态。

11.5  应用托管的EntityManager的持久化上下文

通过表 11-2所总结的各种情况,应用托管EntityManager对象在EJB容器中和Web容器中,可选择的事务类型比较复杂,既可以支持JTA,又可以 支持RESOURCE_LOCAL。下面讲述在这两种情况下,如何控制事务。

11.5.1  无状态的会话Bean与JTA事务(事务范围)

在会话 Bean里以注入的方式获得EntityManagerFactory对象,不需要负责它的关闭,所以此时,只需要控制EntityManager的打开 和关闭。当客户端每次调用Bean中的方法时,都首先创建EntityManager对象,然后在方法结束前关闭EntityManager对象。 EntityManager对象的事务使用的是容器自动管理的事务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  无状态的会话Bean与JTA事务(扩展范围)

与上个 会话Bean中的管理方式不同,此时EntityManager对象为Bean的属性,当Bean初始化后,也就是标注@PostConstruct方法 后,创建EntityManager对象;当Bean销毁前,也就是标注@PreDestroy方法后,关闭EntityManager对象,所以 EntityManager对象是整个的Bean的声明周期中。当客户端调用需要关联事务的方法时,需要使用joinTransaction()方法合并 到上一次的事务中。

代码如下所示。

@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) {

        /**查询不需要关联事务*/

        CustomerEO customer = em.find(CustomerEO.class, customerId);

        em.clear();

        return customer;

    }

    public void placeOrder(Integer customerId, OrderEO order) {

        /**

        *EntityManager 对象的作用范围是这个Bean的生命周期

        *所以,每次使用时要合并到上一次的事务中

        */

        em.joinTransaction();

        CustomerEO customer = em.find(CustomerEO.class, customerId);

        customer.getOrders().add(order);

        em.merge(customer);

        /**

        * 手动脱离当前事务和持久化上下文

        */

        em.flush();

        em.clear();

    }

    @PreDestroy

    public void destroy(){

        em.close();

    }

}

11.5.3  有状态的会话Bean与JTA事务

同样是 EntityManager对象在整个的Bean的声明周期中,但由于会话Bean此时是有状态的Bean,所以当客户端调用任何方法时,都处在同一个持 久化上下文中。所以每次并不需要调用clear()方法来手动地脱离当前的上下文,但每次客户端的调用仍需要使用joinTransaction()方法 合并到上一次的事务中。

代码如下所示。

@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事务

前面三 节的例子讲述的是JTA事务,当在J2SE环境中,必须采用RESOURCE_LOCAL事务,而且需要手动创建和关闭 EntityManagerFactory、EntityManager对象。关联事务时要使用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();

    }

}

分享到:
评论

相关推荐

    JPA核心知识总结

    **JPA核心知识总结** Java Persistence API (JPA) 是Java平台上的一个规范,用于管理和持久化Java对象到关系数据库。它提供了一种面向对象的方式来处理数据,使得开发者可以使用面向对象的编程语言来操作数据库,而...

    01_传智播客JPA详解_全面阐释和精彩总结JPA

    本教程“01_传智播客JPA详解_全面阐释和精彩总结JPA”旨在深入解析JPA的核心概念和技术,帮助开发者全面理解和掌握这一强大的ORM框架。以下是本教程可能涵盖的一些关键知识点: 1. **JPA简介**:介绍JPA的基本概念...

    JPA Demo 简单的了解下jpa

    JPA支持容器管理事务(CMT)和bean管理事务(BMT)。在CMT中,事务由应用服务器自动管理;而在BMT中,开发者需要手动调用`em.getTransaction().begin()`和`.commit()`。 **总结** JPA通过提供ORM能力,使得Java...

    jpa

    2. **事务管理**:JPA支持声明式事务管理,简化了事务处理。 3. **懒加载和即时加载**:通过懒加载机制,可以优化性能,仅在需要时加载关联数据。 4. **级联操作**:允许在操作一个实体时,同时影响到与其关联的其他...

    JPA

    - **事务(Transaction)**:为了确保数据的完整性和一致性,JPA操作通常需要在一个事务的上下文中进行。 ### JPA与Spring框架的整合 在给定的部分内容中,提到了Spring框架与JPA的整合。Spring提供了一种简单的...

    JPA Specification

    - **事务控制**:JPA支持本地事务和分布式事务,可以通过编程式或声明式的方式控制事务的边界。 ##### 4. 高级特性 - **缓存机制**:JPA支持一级缓存(内置缓存)和二级缓存(可选的第三方缓存实现)。这有助于...

    openjpa-manual

    ### OpenJPA-Manual 关键知识点解析 #### 一、OpenJPA介绍 **1.1 关于本文档** ...以上是对“openjpa-manual”文档的关键知识点的总结,希望能帮助读者更好地理解JPA和OpenJPA的相关概念和技术细节。

    springboot + jpa 批量存储示例

    总结,通过Spring Boot和JPA,我们可以方便地进行数据库操作,包括批量存储。通过合理配置连接池如Druid和调整事务策略,可以进一步优化批量操作的性能。同时,对于大数据量的批量处理,记得采用分批保存的方式,以...

    jpa的学习---jpa demo工程

    它定义了一组API,允许开发者定义实体类、关系映射、事务控制等,而无需直接编写SQL语句。 2. **JPA配置** 在Java项目中,JPA的配置通常通过`pom.xml`文件引入依赖,如Spring Data JPA,然后在`application....

    JPA实用讲义

    ### JPA事务管理 JPA支持编程式和声明式事务管理。声明式事务管理通过在方法上添加`@Transactional`注解,让容器自动管理事务的开始、提交或回滚。编程式事务管理则需要手动调用`entityManager.getTransaction()`...

    JPA API 开发手册

    6. **事务管理**: JPA支持声明式和编程式事务管理,可以方便地与Spring等框架集成,实现事务的控制。 7. **懒加载(Lazy Loading)与即时加载(Eager Loading)**: 对于关联的对象,JPA提供了懒加载和即时加载策略...

    Pro JPA 2版

    JPA2提供了丰富的特性,可以处理从简单的CRUD操作到复杂的查询和事务管理。书中第一章“Introduction”将为读者提供JPA2的基本概念介绍,帮助初学者快速入门。 2. 实体管理(EntityManager) 第六章“EntityManager...

    jpa代码自动生成工具-springboot

    总结起来,"jpa代码自动生成工具-springboot"是利用JPA和Spring Boot特性,配合特定工具,帮助开发者快速构建包含领域模型、数据访问、业务逻辑和前端控制的完整应用。通过这种方式,开发者可以更专注于业务创新,而...

    01_JPA详解_全面阐释和精彩总结JPA.zip

    7. **事务管理**:讨论JPA如何处理事务,包括什么是事务边界,以及如何使用`@Transactional`注解进行事务控制。 8. **实体监听器(EntityListeners)**:了解如何使用实体监听器进行实体生命周期事件的监听,如在...

    JPA 2.0jar包及JPA2.0源代码

    9. **事务和并发**:JPA 2.0提供了丰富的事务管理选项,支持不同级别的并发控制策略,如Optimistic Locking(乐观锁)和Pessimistic Locking(悲观锁)。 10. **存储过程**:JPA 2.0允许调用数据库的存储过程,并将...

    Spring-JPA

    总结,Spring-JPA是Spring对JPA的高度集成,极大地简化了数据访问层的开发工作。通过合理的配置和使用,我们可以快速构建高效、易于维护的数据访问层,同时与SSH等其他框架无缝集成,提高开发效率。

    尚硅谷 jpa

    - **persistence.xml 配置**:指定持久化单元的名称、事务类型 (`RESOURCE_LOCAL` 或 `JTA`) 以及 ORM 框架实现。 - **JPA 基本注解**: - `@Entity`:标记类为实体类。 - `@Table`:指定实体类映射的数据库表。 ...

    Spring2.5整合JPA

    5. **配置事务管理**:Spring提供了PlatformTransactionManager接口,通常使用JpaTransactionManager来管理JPA的事务。 6. **使用Repository**:Spring Data JPA提供了一种声明式的方法来定义Repository接口,可以...

Global site tag (gtag.js) - Google Analytics