EJB拦截器和事务生命周期或如何拦截提交/失败事件? [英] EJB Interceptors and transaction lifecycle OR how to intercept a commit/failure event?

查看:151
本文介绍了EJB拦截器和事务生命周期或如何拦截提交/失败事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个EJB拦截器,我遵循Adam Bien建议的BCE模式,即边界上的所有EJB调用开始并完成一个事务,这意味着没有嵌套的EJB调用(可能有嵌套的CDI注入的Bean调用但是那些应该在ejb边界开始的同一个事务中)。



所以在这些ejb边界我有一个拦截器,我想拦截或知道如果EJB的方法调用已经提交了交易? (也就是说,如果EntityManager涉及到COMMIT sql调用被发送到DB并且成功返回)


  1. 我会得到这个信息来自Interceptor的内部?

  2. 如果没有,我如何收到成功提交或失败的事务的通知?

注意:当然,如果我是EJB的客户端,我正在调用该方法,方法调用我知道交易发生了什么事情,但我有兴趣在客户端收到EJB的回复之前拦截。

  @AroundInvoke 
public Object logMethodEntry(InvocationContext ctx)throws Exception {
Object proceed = null;
try {
proceed = ctx.proceed(); 200新新新新旗新新旗新新新旗新新旗新新旗新新旗新新旗新新旗2001-新新新新旗新新旗2001-新新新新新新旗新新旗2001-新新新新新新旗新新旗2001-新新新新新新新Chan旗新旗旗
//是否仍然打开?
返回; X-45454545 X- 20045 X-454545 X-454545 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X-
}
}

[更新]:我接受了一个很好的答案,但事实是,Java EE中没有任何方式收到已经被交易的交易事件。所以无论好的答案,可惜的是,没有办法在Java EE中通知一个完成的事务,在服务器内部,当然如果你是客户端的调用者,那么你确定知道事务被提交或回滚了

解决方案

除非另有说明,否则抛出异常,如果ejb方法调用引发异常,则它将被回滚。另外,如果对数据库的所有调用都处于同一个事务中,则在交易周期结束时,它们将被视为已被提交。



回想起来,所有拦截器都将被调用调用它截取的ejb方法的同一个事务被调用(这就是拦截器在异常事件中可能决定的原因,要么回滚或者仍然提交事务)。



因此,您可以肯定地知道,如果在拦截器调用中,如果在调用和返回进程之后,事务成功完成,则抛出异常,并且可能会有事务回滚。



所以在您的方案中:

  @AroundInvoke 
public Object logMethodEntry InvocationContext ctx)throws Exception {
Object proceed = null;
try {
proceed = ctx.proceed(); 200新新新新旗新新旗新新新旗新新旗新新旗新新旗新新旗新新旗2001-新新新新旗新新旗2001-新新新新新新旗新新旗2001-新新新新新新旗新新旗2001-新新新新新新新Chan旗新旗旗
//事务成功,但afaik,它还没有提交,直到这个方法成功返回
//是否仍然打开?或多或少。您还可以抓住Ejbtransaction并手动提交它,或者如果还没有满足其他条件,则返回
返回;
} catch(Exception e){
//如果发生这种情况,并且传播它,那么肯定事务将被回滚,并且永远不会被提交。新评新新新旗新新新旗新新旗新新旗新新旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗新旗新新旗新新旗新新旗200新新新200 Chanol旗新新旗新新200新新旗新新新旗新新旗新新旗新新旗新新旗旗哨旗新新旗新
}
}

编辑:
为您实际提交交易在拦截器中,您将需要运行应用程序管理的事务,否则EJB规范禁止在容器管理事务上调用commit,您当然可以调用setOnrollback方法EJBContext。
修改
如果您真的想做一些数据库更改,我建议:


  1. 用户ApplicationManaged事务,从中手动启动
    并在拦截器内提交事务

  2. 使用观察者的概念,并监听@Observes(AFTER_SUCCESS)事件,当
    事务成功提交并完成时,将被调用,因此您可以保证
    执行db调用,新的更新将为

  3. 如果您可以忽略BCE模式,并分拆一个新的事务来进行更新,这样在成功返回后,您将被保证提交,然后继续正常

```

  @Stateless 
public class TransactionService {

@TransactionAttribute(REQUIRES_NEW)
public Object executeTransaction(final Callable< Object> task){
return task.call();
}
}

@Interceptor
public class MyInterceptor {

@EJB
private TransactionService service;

@AroundInvoke
public Object logMethodEntry(InvocationContext ctx)throws Exception {
Object proceed = null;
try {
proceed = service.executeTransactional(() - > ctx.proceed());
//如果你到达这里,你将保证提交,然后你可以做弹性搜索更新
返回继续;
} catch(Exception e){
//如果发生这种情况,并且传播它,那么肯定事务将被回滚,并且永远不会被提交。新评新新新旗新新新旗新新旗新新旗新新旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗旗新新旗新旗新新旗新新旗新新旗200新新新200 Chanol旗新新旗
throw e;
}
}
}


I have an EJB interceptor and I follow the BCE pattern suggested by Adam Bien, that is, all EJB calls on the boundary starts and finish a transaction which means there is no nested EJB calls (there might be nested CDI injected Bean calls though, but those should be inside the same transaction started at the ejb Boundary).

So in those ejb Boundaries I have an interceptor and I want to intercept or know if after the method call of the EJB the transacction commited already? (that is, if a EntityManager was involved that the COMMIT sql call was sent to the DB and returned succeesfuly)

  1. Will I get that info from inside an Interceptor ?
  2. If not, how can I get notified of a transaction that sucessfully commited or failed ?

NOTE: Of course, if I am the client of the EJB and I am calling the method, after the method call I know what happened with the transaction, but I am interested in intercepting that BEFORE the client receives the response from the EJB.

@AroundInvoke
public Object logMethodEntry(InvocationContext ctx) throws Exception {
    Object proceed = null;
    try {
        proceed = ctx.proceed();
        // is the transacction finished/commited already?
        // is it still open ?
        return proceed;
    } catch (Exception e) {
        throw e;
    }
}

[UPDATE]: I accepted one good answer, but the thing is that THERE IS NO WAY in Java EE to receive an event of a transaction that HAS BEEN COMMITED. So regardless of the good answer, sadly there is no way to be notified in Java EE of a completed transaction, inside the server, of course, if you are the client caller, then you sure know the transaction commited or rolled back...

解决方案

unless otherwise stated on the exception thrown, if an ejb method invocation throws an exception, it shall be rolled-back. Additionally, provided all calls to the DB were in the same transaction, they shall be deemed committed at the end of the transaction cycle.

In retrospect, all interceptors are invoked within the same transaction on which the ejb method it intercepts, was invoked (That's the reason the interceptor may decide in an event of an exception, to either roll-back or still commit the transaction).

Hence, you can know for sure, that the transaction completed successfully if within your interceptor call, after the proceed has been invoked and returned, there is no exception thrown, with a potential of transaction rollback.

So in your scenario:

@AroundInvoke
public Object logMethodEntry(InvocationContext ctx) throws Exception {
    Object proceed = null;
    try {
        proceed = ctx.proceed();
        // is the transacction finished/commited already?
        // The transaction is successful, but afaik, it is not yet committed, until this method returns successfully
        // is it still open ? More or less. You can still grab the Ejbtransaction and commit it manually or rollback if some other conditions have not been met yet
        return proceed;
    } catch (Exception e) {
        //If this happens, and you propagate it, then for sure the transaction will be rolledback, and never get committed. Since all db calls were being done within this transaction, then no DB commit will be done.
        throw e;
    }
}

Edit: for you to actually commit the transaction in an interceptor, you will need to be running application-managed transaction, otherwise, it is prohibited by the EJB specs to call commit on a container managed transaction, you can of course call setOnrollback method of the EJBContext. Edit If you truly want to do some DB changes, i would recommend:

  1. user ApplicationManaged transaction, from which you manually start and commit the transaction within the interceptor
  2. Use the concept of the observer, and listen for @Observes(AFTER_SUCCESS) event which will be invoked when the transaction is successfully committed and complete, and hence you can be guaranteed to do a db call, and the new updates will be available.
  3. If you can ignore the BCE pattern, and spin off a new transaction to do the update, so that after it returns successfully, you will be guaranteed of commit, and then continue normally

```

@Stateless
public class TransactionService {

   @TransactionAttribute(REQUIRES_NEW)
   public Object executeTransaction(final Callable<Object> task) {
       return task.call();
   }
}

@Interceptor
public class MyInterceptor {

  @EJB
  private TransactionService service;

   @AroundInvoke
    public Object logMethodEntry(InvocationContext ctx) throws Exception {
        Object proceed = null;
        try {
            proceed = service.executeTransactional(()->ctx.proceed());
            //If you reach here, you will be guaranteed of commit and then you can do the elastic search update
            return proceed;
        } catch (Exception e) {
            //If this happens, and you propagate it, then for sure the transaction will be rolledback, and never get committed. Since all db calls were being done within this transaction, then no DB commit will be done.
            throw e;
        }
    }
}

这篇关于EJB拦截器和事务生命周期或如何拦截提交/失败事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆