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对象所支持的事务类型。
运行环境
J2EE环 境
J2SE环 境
类型
EJB容 器
Web容 器
应用托管的EntityManager
JTA,RESOURCE_LOCAL
JTA,RESOURCE_LOCAL
RESOURCE_LOCAL
容器托管的EntityManager
JTA
不支持
不支持
表11-2 事务类型与EntityManager
运行环境
类型
J2EE环 境
J2SE环 境
EJB容 器
Web容 器
应用托管的EntityManager
JTA,RESOURCE_LOCAL
JTA,RESOURCE_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中另一项重要的内容,了解了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对象所支持的事务类型。
运行环境
J2EE环 境
J2SE环 境
类型
EJB容 器
Web容 器
应用托管的EntityManager
JTA,RESOURCE_LOCAL
JTA,RESOURCE_LOCAL
RESOURCE_LOCAL
容器托管的EntityManager
JTA
不支持
不支持
表11-2 事务类型与EntityManager
运行环境
类型
J2EE环 境
J2SE环 境
EJB容 器
Web容 器
应用托管的EntityManager
JTA,RESOURCE_LOCAL
JTA,RESOURCE_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();
}
}
发表评论
-
javascript各种特效下载
2011-12-13 11:08 833javascript各种特效 -
java api 中英文帮助文档
2011-12-09 12:16 0Sun 公司提供的Java API Doc ... -
java的几种对象(PO,VO,DAO,BO,POJO)解释
2011-12-09 11:22 738java的几种对象(PO,VO,DAO,BO,POJO)解释 ... -
各种学习网站
2011-12-07 12:17 924Oracle 权限 http://blog.sina.com. ... -
java序列化
2011-12-01 09:48 794序列化(Serialization)也叫串行化,是Java内置 ... -
线程的启动,暂停和终止
2011-12-01 09:41 1495线程的启动暂停和终止,听起来很简单,不过经常有初学者在这个问题 ... -
如何提升JAVA技术开发能力—JAVA学习25个关注点
2011-11-30 17:56 7691.你需要精通面向对象 ...
相关推荐
Spring-data-jpa 是 Spring 家族中的一个重要成员,它主要用于简化基于 Java Persistence API (JPA) 的数据访问层(DAO)的开发工作。JPA 作为 Java 平台的一种标准,旨在为 Java 应用程序提供一种通用的对象关系...
JPA(Java Persistence API)是Java EE(现在是Jakarta EE)的一部分,提供了对象关系映射的标准化。Spring Data JPA 可以看作是对 JPA 的进一步封装和简化,它能够帮助开发者更快地实现对数据的增删改查操作。 在...
1. **JPA 整合**:Spring Data JPA 提供了与 JPA 规范的无缝集成,包括实体管理、事务管理和数据源配置。 2. **EntityManager 和 Repository**:Spring Data JPA 封装了 `EntityManager` 和 `EntityTransaction`,...
- 配置 JPA 实体管理工厂 (`EntityManagerFactory`) 和事务管理器 (`PlatformTransactionManager`)。 - 使用 `@EnableJpaRepositories` 注解启用 JPA 存储库的自动配置。 - 数据源配置,连接到相应的数据库。 5....
在eladmin jpa版本中,JPA使得数据库操作变得更加简单,提供了CRUD(创建、读取、更新、删除)操作的便利性,并支持事务管理和查询表达式。 【Spring框架】是Java开发中的核心框架,它提供了依赖注入、AOP(面向切...
- **事务管理**:Spring Data JPA 集成了 Spring 的事务管理功能,可以轻松地在 Repository 层处理事务边界。 #### 三、Repository 接口 ##### 1.3 Query Methods - **定义 Repository 接口**:定义一个继承自 `...
8. **数据持久化**:理解JPA的保存(`save()`)、更新(`saveAndFlush()`)、查询(`findAll()`, `findById()`等)、删除(`deleteById()`)等操作的工作原理,以及事务管理的概念。 这个"springboot-spring-data-...
Spring Data JPA 是 Spring Framework 的一部分,它提供了针对 Java Persistence API (JPA) 的高级数据访问功能。JPA 是 Java 社区定义的一个标准,用于管理关系数据库中的数据。它通过 ORM(对象关系映射)机制,将...
**JPA(Java Persistence API)学习——JPA Demo工程** JPA是Java平台上的一个标准,用于处理对象关系映射(ORM),它提供了一种在Java应用中管理和持久化对象的方式,简化了数据库操作。本篇文章将围绕JPA的基础...
在Spring Boot应用中,使用`spring-data-jpa`来配置MySQL多数据源是一项常见的需求,尤其是在构建大型分布式系统时,为了...在实际项目中,可能还需要考虑事务管理、数据源切换策略等问题,确保系统的稳定性和高性能。
而 JPA(Java Persistence API)是 Java 平台上的对象关系映射标准,它为应用程序提供了一种透明地访问数据库的方式,无需编写大量 SQL 代码。 在"最基础的spring-boot-jpa框架"中,我们可以深入探讨以下几个关键...
【标题】"spring-data-jpa-examples-master.rar_spring data jpa" 提供了一个关于Spring Data JPA的实际应用示例,这是一个广泛使用的Java框架,它简化了与数据库的交互,特别是通过JPA(Java Persistence API)进行...
Spring Data JPA 是一个强大的框架,它简化了Java Persistence API (JPA) 的使用,并提供了一种简单的方式来执行数据访问操作。该框架的核心思想是通过定义接口来实现对数据库的操作,而不是编写具体的实现代码,这...
Spring Data JPA 是 Spring 基于 Java Persistence API (JPA) 提供的一个数据访问/集成框架,它极大地简化了数据库操作。JPA 是 Java 平台上的一个标准,用于管理关系数据库中的对象,提供了一种面向对象的方式来...
标题 "cursomc-java-spring-jpa" 暗示了这是一个关于使用Java、Spring框架和JPA(Java Persistence API)的课程或项目。这个项目可能是一个教学资源,帮助学习者理解如何在Spring环境中有效地集成JPA进行数据库操作...
Java Persistence API (JPA) 是Java企业级应用中用于对象关系映射(ORM)的标准框架。ORM的主要目标是解决在关系数据库与面向对象编程之间的不匹配问题,使得开发者可以更自然地使用对象而不是直接操作表格数据。JPA...
Spring Data JPA是Spring框架的一个模块,专门用于简化Java Persistence API (JPA)的使用,为开发者提供了便捷的数据访问层的实现方式。本教程将深入探讨Spring Data JPA的常见用法,帮助开发者快速上手并高效地进行...
根据提供的文档信息,“spring-data-jpa-reference.pdf”主要围绕Spring Data JPA展开,涉及其基本概念、使用方法以及一些高级特性。以下是对该文档中提到的一些关键知识点的详细阐述: ### 一、Spring Data JPA...
Spring Data JPA 是 Spring Data 的一部分,它简化了基于 Java Persistence API (JPA) 的数据访问层开发工作。Spring Data 旨在减少数据访问层的编码量,通过提供一套统一的方式来与各种类型的数据存储进行交互,...