JPA 2.1:不同步的持久性上下文

本文介绍了JPA 2.1中新的持久性上下文处理方式,它允许禁用与JTA事务的自动同步。默认情况下,容器管理的持久性上下文自动加入当前JTA事务,但在新类型下,需要手动调用`joinTransaction()`方法。这种变化使得在有状态会话Bean中实现跨越多个方法调用的对话变得更加灵活,并能根据动态逻辑决定何时加入事务。
摘要由CSDN通过智能技术生成

JPA 2.1版带来了一种新的方式来处理持久性上下文与当前JTA事务以及资源管理器之间的同步。 术语资源管理器来自Java事务处理API ,它表示操纵一个资源的组件(例如,使用JDBC驱动程序操纵的具体数据库)。 默认情况下,容器管理的持久性上下文的类型为SynchronizationType.SYNCHRONIZED ,即,该持久性上下文自动加入当前的JTA事务,并将对持久性上下文的更新传播到基础资源管理器。

通过创建新类型为SynchronizationType.UNSYNCHRONIZED的持久性上下文,将禁用事务的自动连接以及将更新传播到资源管理器。 为了加入当前的JTA事务,代码必须调用EntityManager joinTransaction()方法。 这样,EntityManager的持久性上下文将在事务中登记,并为后续通知注册。 提交或回滚事务后,持久性上下文将离开事务,并且不会附加到任何其他事务,直到再次为新的JTA事务调用joinTransaction()方法joinTransaction()

JPA 2.1之前,一个可以实现与一个跨越多个方法调用的对话@Stateful由亚当边描述会话Bean 在这里

@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class Controller {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    EntityManager entityManager;
 
    public Person persist() {
        Person p = new Person();
        p.setFirstName("Martin");
        p.setLastName("Developer");
        return entityManager.merge(p);
    }
 
    public List<Person> list() {
        return entityManager.createQuery("from Person", Person.class).getResultList();
    }
 
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void commit() {
         
    }
 
    @Remove
    public void remove() {
 
    }
}

持久性上下文的类型为EXTENDED ,因此,其生存期比它所附加的JTA事务的寿命长。 由于持久性上下文默认也是SYNCHRONIZED类型,因此它将在调用任何会话bean方法时自动加入正在运行的任何事务。 为了防止大多数Bean方法发生这种情况,注释@TransactionAttribute(TransactionAttributeType.NEVER)告诉容器不要为此Bean打开任何事务。 因此,方法persist()list()无需事务即可运行。 对于方法commit()此行为是不同的。 这里的注释@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)告诉容器在调用该方法之前创建一个新事务,因此Bean的EntityManager将自动加入该事务。

使用新的SynchronizationType.UNSYNCHRONIZED类型,可以如以下清单所示重写上面的代码:

@Stateful
public class Controller {
    @PersistenceContext(type = PersistenceContextType.EXTENDED,
        synchronization = SynchronizationType.UNSYNCHRONIZED)
    EntityManager entityManager;
 
    public Person persist() {
        Person p = new Person();
        p.setFirstName("Martin");
        p.setLastName("Developer");
        return entityManager.merge(p);
    }
 
    public List<Person> list() {
        return entityManager.createQuery("from Person", Person.class).getResultList();
    }
 
    public void commit() {
        entityManager.joinTransaction();
    }
 
    @Remove
    public void remove() {
 
    }
}

现在,EntityManager不会自动加入当前事务,我们可以省略@TransactionAttribute批注。 在我们明确加入之前,任何正在运行的事务都不会对EntityManager产生影响。 现在,这是在commit()方法中完成的,甚至可以基于某些动态逻辑来完成。

为了测试上面的实现,我们利用了一个简单的REST资源:

@Path("rest")
@Produces("text/json")
@SessionScoped
public class RestResource implements Serializable {
    @Inject
    private Controller controller;
 
    @GET
    @Path("persist")
    public Person persist(@Context HttpServletRequest request) {
        return controller.persist();
    }
 
    @GET
    @Path("list")
    public List<Person> list() {
        return controller.list();
    }
 
    @GET
    @Path("commit")
    public void commit() {
        controller.commit();
    }
 
    @PreDestroy
    public void preDestroy() {
 
    }
}

该资源提供了持久化人员,列出所有持久化人员并提交当前更改的方法。 当我们要使用有状态会话Bean时,我们用@SessionScoped注释资源,然后让容器注入Controller Bean。

在将应用程序部署到某个Java EE容器之后,通过调用以下URL,一个新人员将被添加到非同步的持久性上下文中,但不会存储在数据库中。

http://localhost:8080/jpa2.1-unsychronized-pc/rest/persist

即使调用list()方法也不会返回新添加的人员。 只有最终通过调用commit()将持久性上下文中的更改与基础资源同步,才将insert语句发送到基础数据库。

结论

持久性上下文的新UNSYNCHRONIZED模式使我们可以在不止一个有状态会话bean的方法调用上实现对话,并且可以灵活地根据我们的应用程序逻辑动态地加入JTA事务,而无需任何注释魔术。

翻译自: https://www.javacodegeeks.com/2015/03/jpa-2-1-unsynchronized-persistence-context.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值