什么是在EJB中获取多个事务的干净,标准方法?

时间:2017-05-08 18:40:02

标签: java-ee ejb bulk transactional

我有batchEdit(List<E> entity)在循环中调用edit(E entity)函数,而每个edit()都有自己的事务,因此失败的编辑不会回滚良好的编辑。我目前的实现方式如下:

选项1

@Stateless
@TransactionManagement( value = TransactionManagementType.CONTAINER )
public class Service<E> {

    @Resource
    private SessionContext context;

    @Override
    @TransactionAttribute( value = TransactionAttributeType.REQUIRES_NEW )
    public E edit( E entity ) {
       //edit code
    }

    @Override
    public List<E> bulkEdit( List<E> entities ) {
       for(E entity : entities){
          //case 1: Regular edit, Does not create a new transaction!
          //edit(entity);

          //case 2: Hacky edit, creates a new transaction
          context.getBusinessObject( Service.class ).editPersistNulls( entity );
       }
    }
}

根据this stackoverflow discussion@TransactionAttribute在我的情况1中被忽略,因为它没有跨越任何EJB边界,因此batchEdit()调用edit()就好像它一样没有注释。使用案例2中的context.getBusinessObject()函数来获取bean的引用会导致TransactionManagement批注生效,但是完成所有这些操作似乎很奇怪。

选项2

我的另一个选择是更改为bean托管交易:

@TransactionManagement( value = TransactionManagementType.BEAN )

然后我会失去&#34; JPA Magic&#34;并且必须管理各地的交易。我不认为我团队中的其他人会想要通过它,所以如果有更好或更标准的方法来做到这一点,那么任何见解都会受到赞赏。

我们正在使用OpenJPA和EJB,但我们正试图接近JPA标准。

2 个答案:

答案 0 :(得分:1)

你可以在自己注入EJB。

@Stateless
public class Service<E> {

    @EJB
    private Service<E> self;

    @TransactionAttribute(REQUIRES_NEW)
    public void edit(E entity) {
        // ...
    }

    @TransactionAttribute(NOT_SUPPORTED)
    public void bulkEdit(List<E> entities) {
        for (E entity : entities) {
           self.edit(entity);
        }
    }
}

更好的做法是@Asynchronous。它更快。

@Stateless
public class Service<E> {

    @EJB
    private Service<E> self;

    public void edit(E entity) {
        // ...
    }

    @Asynchronous
    @TransactionAttribute(REQUIRES_NEW)
    public void asyncEdit(E entity) {
        // ...
    }

    @TransactionAttribute(NOT_SUPPORTED)
    public void bulkEdit(List<E> entities) {
        for (E entity : entities) {
           self.asyncEdit(entity);
        }
    }
}

它还使原始edit()方法不受可能不需要的REQUIRES_NEW事务属性的影响,因为它可能从其他服务调用,当然应该保留在同一事务中。对于@Asynchronous,在每次调用时都需要新的事务更有意义。

答案 1 :(得分:0)

我想那&#34; hacky&#34;是在旁观者的眼中。 context.getBusinessObject恰好存在,你可以做这种事。

另一种方法是使用第二类:

@Stateless
public class BulkService<E> {

    @EJB
    private Service<E> service;

    public List<E> bulkEdit( List<E> entities ) {
       for(E entity : entities) {
           service.editPersistNulls( entity );
       }
    }

}

请注意大型实体列表,因为您的包含事务可能会超时。

如果您正在使用符合Java EE 7的服务器实施,请考虑使用JSR-352 Batch Applications支持。