【问题标题】:Container Managed Transaction - Not marked for roll back容器管理事务 - 未标记为回滚
【发布时间】:2020-10-08 10:15:45
【问题描述】:

Bank.java

@Stateless
@Local
public class Bank implements IBank {

    @EJB
    IConfigBean iConfigBean;

    @EJB
    IDbs iDBS;

    @EJB
    IPosb iPosb;

    @Override
    public void doTransaction() {
        System.out.println("--Bank Transaction Started--");
        try {
            Config config1 = getConfig(1);
            iConfigBean.create(config1);

            iDBS.doDBSTransaction();

            Config config3 = getConfig(3);
            iConfigBean.create(config3);

            iPosb.doPOSBTransaction();

            Config config5 = getConfig(5);
            iConfigBean.create(config5);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("---Bank Exception--");
        }
        System.out.println("--Bank Transaction End--");
    }

    @Override
    public Config getConfig(int inserttionOrderNo) {
        Config config = new Config();
        config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
        return config;
    }
}

DBS.java

@Stateless
@Local
public class DBS implements IDbs {

    @EJB
    IConfigBean iConfigBean;

    @Override
    public void doDBSTransaction() {
        System.out.println("--DBS Transaction Started--");
        try {
            Config config2 = getConfig(2);
            iConfigBean.create(config2);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("--DBS Exception--");
        }
        System.out.println("--DBS Transaction End--");
    }

    @Override
    public Config getConfig(int inserttionOrderNo) {
        Config config = new Config();
        config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
        return config;
    }

}

POSB.java

@Stateless
@Local
public class POSB implements IPosb {

    @EJB
    IConfigBean iConfigBean;

    @Override
    public void doPOSBTransaction() {
        System.out.println("--POSB Transaction Started--");
        try {
            Config config4 = getConfig(4);
            iConfigBean.create(config4);
            if (true) {
                //For Test 1 
                //throw new NullPointerException(); 
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("--POSB Exception--");
        }
        if (true) {
            //For Test 2 
            // throw new NullPointerException();
        }
        System.out.println("--POSB Transaction End--");
    }

    @Override
    public Config getConfig(int inserttionOrderNo) {
        Config config = new Config();
        config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
        return config;
    }
}

我是 Stack Overflow 的新手,这是我的新问题,如果我错了,请纠正我。

环境是..

  • Windows 10
  • Java 1.8
  • 日食
  • Tomcat 8.5
  • EJB3

我有三个无状态bean,请看Transaction流的Sequence Diagram

我在交易过程中故意在两个地方制作了 NullPointer Exception 以了解区别,并在序列图中用 Lightening Bold 符号标记。

我没有对任何方法使用任何@TransactionAttribute。

测试 1 - try 块内的空指针(带绿色的闪电粗体符号) 当我开始测试时,出现空指针异常并且所有事务都没有标记为回滚,并且数据也被插入到数据库中。

我只能在控制台日志中看到空指针异常。

测试 2 - 在 try - catch 方法之外的空指针(带红色的闪电粗体符号) 当我开始测试时,得到空指针异常加上 EJBTransactionRolledbackException 和所有标记为回滚的事务并且没有数据插入到数据库中。

我可以在控制台日志中看到 NullPointer 和 EJBTransactionRolledback 异常。

这里的问题是,

  1. 如果我在 try 块中创建了 Null 指针,为什么 EJB 事务没有标记为回滚
  2. 如果我在 try 块之外创建了空指针,为什么会发生 EJB 事务回滚

提前致谢。

【问题讨论】:

    标签: java jpa ejb ejb-3.0 openjpa


    【解决方案1】:

    记住 EJB 调用,容器创造的所有“魔法”都发生在那里,包括事务标记。这可能是因为 EJB 调用不是直接的,而是始终通过代理。

    你的代码中有这样的调用:

    iPosb.doPOSBTransaction(); 
    

    因此,如果在此方法中抛出未经检查的异常(例如 NPE)并且未捕获 - 由于 EJB 代理包装了上面的调用,它最终会被容器捕获。在这种情况下,事务只能回滚。

    在您的方法中添加对同一 bean 的方法的调用(不使用 @EJB 引用)不会改变这一点:

    @Override
    public void doPOSBTransaction() {
        try {
            Config config4 = getConfig(4);
            iConfigBean.create(config4);
            if (true) {
                newMethod(); 
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("--POSB Exception--");
        }
        if (true) {
            newMethod(); 
        }        
    }
    
    private void newMethod(){
        throw new RuntimeException();
    }
    

    在这种情况下,您可以轻松检查提交/回滚行为是否相同,无论是否将方法添加到调用堆栈。

    因此,您必须记住的重要一点是,所有容器技巧仅适用于 @EJB 调用。因此,例如,将事务注释放在私有方法上是没有意义的——它永远不会被使用。

    另一个重要的一点是关于检查的异常。默认情况下,这些确实不会导致事务回滚。但是仍然可以像下面这样注释您的检查异常以使其回滚正在进行的事务:

    @ApplicationException(rollback = true) 
    

    【讨论】:

    • 您好,感谢您回答我的问题,这对我也有帮助。在另一件事上需要你的帮助。我想将 Bank 类、DBS 类 Config 对象的数据持久化到配置表中,但我不想将 POSB 类 Config 对象持久化到配置表中,因为 POSB 类方法 doPOSBTransaction 发生了 RuntimeException 所以我想省略这个 doPOSBTransaction 方法交易,我想提交其余的事情。请帮助理解实现上述场景的事情。
    • @Rawoof 请将此作为一个新问题发布,并提供更多详细信息,但还不够清楚。
    • 嗨@user3714601,好的,谢谢
    猜你喜欢
    • 1970-01-01
    • 2015-11-25
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多