@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)不起作用

时间:2015-06-22 11:46:34

标签: java jpa glassfish ejb-3.0

我需要在glassfish3.0上使用JPA 2.0和EJB3.0删除忽略任何完整性约束的员工列表(即成功删除与其他任何其他人无关的实体或跳过与其他人相关的实体) :

我在列表上迭代并在try / catch中的require_new事务中调用实体管理器,我希望这将在大事务中打开小嵌套事务,并使用em.flush()来强制更新。

但是在它抛出的相关实体的迭代中;

  

异常[EclipseLink-4002](Eclipse持久性服务 -   2.4.2.v20130514-5956486):org.eclipse.persistence.exceptions.DatabaseException内部   例外:   com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:   无法删除或更新父行:外键约束失败

并继续下一个员工,但在提交大事务时,它会回滚并抛出相同的异常!

我希望在new-small事务中抛出/捕获异常并提交列表其余部分的成功删除实体...

我错过了什么吗?

编辑:

这是一些代码,Facade中的代码调用实体管理器来删除bean,我通过required-new注释该函数:

 public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {

        Iterator itr;
        Employees emp;


        //delete unused recordes 
        try {

            itr = deleted.iterator();

            while (itr.hasNext()) {
                emp = (Employees) itr.next();
                deleteEmployee(emp);                
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("DONE");
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    private void deleteEmployee(Employees emp){
        try {
                    this.remove(emp);
                } catch (Exception ex) {
                    System.out.println(ex.getMessage());
                }

    }

3 个答案:

答案 0 :(得分:4)

deleteEmployee方法未包装到新事务中,因为您在this上引用方法。您可以做的是注入外观本身,然后在其上调用deleteEmployee方法(它应该是公开的)。

或多或少这样的事情:

@Stateless
public class MyFacade {
    @EJB
    private MyFacade self;

   public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {
     ...
     try {
       self.deleteEmployee(emp);
     } catch (Exception ex) {
       // ...
     }
     ...
   }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void deleteEmployee(Employees emp) {
      this.remove(emp);
    }

}

答案 1 :(得分:1)

您的问题似乎是您希望在try catch中以编程方式捕获事务错误但事务传播是声明性的(使用注释),这通常会创建一个代理堆栈并透明地处理事务失败。您需要使用程序化事务并将其包装在异常处理代码中。

答案 2 :(得分:1)

调用本地方法并用新事务包装它,

@Stateless
public class UserFacade implements UserFacadeLocal {
@Resource
private SessionContext context;

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void create(User user) {
        System.out.println("Users Count: "+count()); //invocation#1
        System.out.println("Users Count Through Context: "+context.getBusinessObject(UserFacadeLocal.class).count()); //invocation#2
    }

@Override
@TransactionAttribute(TransactionAttributeType.NEVER)
    public int count() {
        return ((Long) q.getSingleResult()).intValue();
    }
}

EJB Transactions in local method-calls