我有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标准。
答案 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支持。