如何对EJB3事务提交或回滚做出反应? [英] How to react on a EJB3 transaction commit or rolleback?

查看:94
本文介绍了如何对EJB3事务提交或回滚做出反应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已将Service实现为无状态会话EJB(3.2),以通过JPA存储数据.另外,每次更新数据时,EJB也会更新Lucene索引.会话Bean由容器管理. ejb的代码如下:

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // update Lucene index
        ....
    }
    ....
} 

我有不同的其他BusinessService-EJB调用此DataService EJB来插入或更新数据.我无法控制BusinessService-EJB的实现.由BusinessService-ejb启动的事务可以包含对DataService EJB的save()方法的多次调用.

@Stateless
@LocalBean
public class SomeBusinessService {
    @EJB
    DataService dataService;
    ....

    public void process(....)  {
        dataService.save(data1);
        ...
        dataService.save(data2);
        ....
    }
    ....
} 

如果BusinessService-EJBs方法进程"中断,则会发生我的问题. DataService.save()的每个方法调用都会更新给定数据对象的Lucene索引.但是,如果以后的调用之一失败,则将回滚完整的事务.我的JPA工作将按预期回滚(不将任何数据写入数据库).但是,在取消交易之前,已经为save()方法的所有成功完全调用更新了Lucene索引.

所以我的问题是:在DataService EJB中如何应对这种情况?这有可能吗?

我看到,使用Statefull Session EJB 3.2,我可以使用注释"@AfterCompletion"对方法进行注释.因此,我猜想这可能仅在使用'success'调用@AfterCompletion时才可以编写lucene索引的解决方案.但是,无状态会话EJB不允许使用此注释. 我是否应该将EJB类型从无状态更改为有状态? 但是,这如何影响我仍然使用无状态会话EJB的BusinessService-EJB的情况?这行得通吗?我还担心将我的ejb形式从无状态更改为有状态将对性能产生影响.

还是有其他方法可以解决此问题?例如,侦听器根据事务ID编写日志,并在事务完全完成后更新lucene索引.


2018-08-29-解决方案:

我通过以下方式解决了这个问题:

我没有在我的方法DataService.save(data)期间直接更新Lucene索引,而是使用相同的事务使用JPA创建了一个新的eventLogEntry.

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // Write a JPA eventLog entry indicating to update Lucene index
        ....
    }
    ....
} 

现在,每当客户端调用lucene搜索方法时,我都会根据事件日志条目运行flush方法来更新我的lucene索引:

@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void flush() {
    Query q = manager.createQuery("SELECT eventLog FROM EventLog AS eventLog" );
    Collection<EventLog> result = q.getResultList();
    if (result != null && result.size() > 0) {

        for (EventLog eventLogEntry : result) {
            .... update lucen index for each entry
            .......
            // remove the eventLogEntry.
            manager.remove(eventLogEntry);
        }
    }
}

带有注释TransactionAttributeType.REQUIRES_NEW的flush()方法将仅读取已提交的eventLog条目.

因此,客户端将仅在Lucene索引中看到已提交的更新.即使在从我的一个BusinessService-EJB进行交易时,lucene也不会包含未刷新"的文档.此行为等同于事务模型已读".

另请参见类似的讨论:如何进行无状态会话bean可以识别交易吗?

解决方案

我通过以下方式解决了这个问题:

我没有在我的方法DataService.save(data)期间直接更新Lucene索引,而是使用相同的事务使用JPA创建了一个新的eventLogEntry.

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // Write a JPA eventLog entry indicating to update Lucene index
        ....
    }
    ....
} 

现在,每当客户端调用lucene搜索方法时,我都会运行flush方法根据事件日志条目更新我的lucene索引:

@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void flush() {
    Query q = manager.createQuery("SELECT eventLog FROM EventLog AS eventLog" );
    Collection<EventLog> result = q.getResultList();
    if (result != null && result.size() > 0) {

        for (EventLog eventLogEntry : result) {
            .... update lucen index for each entry
            .......
            // remove the eventLogEntry.
            manager.remove(eventLogEntry);
        }
    }
}

带有注释TransactionAttributeType.REQUIRES_NEW的flush()方法将仅读取已提交的eventLog条目.

因此,客户端将仅在Lucene索引中看到已提交的更新.即使在从我的一个BusinessService-EJB进行交易时,lucene也不会包含未刷新"的文档.此行为等同于事务模型已读".

另请参见类似的讨论:如何进行无状态会话Bean可以识别交易吗?

I have implemented a Service as a stateless session EJB (3.2) to store data via JPA. In addition the EJB also updates a Lucene Index each time data is updated. The session bean is container managed. The code of the ejb looks like this:

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // update Lucene index
        ....
    }
    ....
} 

I have different other BusinessService-EJBs calling this DataService EJB to insert or update data. I have no control over the BusinessService-EJB implementations. A transaction started by a BusinessService-ejb can contain several calls of the save() method of my DataService EJB.

@Stateless
@LocalBean
public class SomeBusinessService {
    @EJB
    DataService dataService;
    ....

    public void process(....)  {
        dataService.save(data1);
        ...
        dataService.save(data2);
        ....
    }
    ....
} 

My problem occurs if the BusinessService-EJBs method 'process' breaks. Each method call of DataService.save() updates the Lucene index of the given data object. But if one of the later calls fails the full transaction is rolled back. My JPA work will be rolled back as expected (no data is written to the database). But the Lucene index is now already updated for all the success full calls of the save() method before the transaction was canceled.

So my question is: How can I react on such a situation within my DataService EJB? Is this even possible?

I saw that with a Statefull Session EJB 3.2 I can annotate a method with the annotation "@AfterCompletion". So I guess that this could probably be a solution to write the lucene index only if @AfterCompletion is called with 'success'. But this annotation is not allowed for Stateless Session EJBs. Should I simply change my EJB type from stateless to statefull? But how does this affect my scenario with the BusinessService-EJB which is still a stateless session EJB? Would this work? I also fear that changing my ejb form stateless to statefull will have a performance impact.

Or is there any other way to solve this problem? For example something like a listener writing a log based on the transaction ID, and updating the lucene index after the transaction was fully completed....?


2018-08-29 - Solution:

I solved this problem in the following way:

Instead of directly updating the Lucene index during my method DataService.save(data) I just create a new eventLogEntry with JPA using the same transcation.

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // Write a JPA eventLog entry indicating to update Lucene index
        ....
    }
    ....
} 

Now whenever a client calls the lucene search method, I run a flush method to update my lucene index based on the event log entries:

@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void flush() {
    Query q = manager.createQuery("SELECT eventLog FROM EventLog AS eventLog" );
    Collection<EventLog> result = q.getResultList();
    if (result != null && result.size() > 0) {

        for (EventLog eventLogEntry : result) {
            .... update lucen index for each entry
            .......
            // remove the eventLogEntry.
            manager.remove(eventLogEntry);
        }
    }
}

With the annotation TransactionAttributeType.REQUIRES_NEW the flush() method will only read already committed eventLog entries.

So a client will only see committed updates in the Lucene Index. Even during a transaction from one of my BusinessService-EJBs the lucene will not include 'unflushed' documents. This behavior is equals to the transaction model 'Read Committed'.

See also the similar discussion at: How making stateless session beans transaction-aware?

解决方案

I solved this problem in the following way:

Instead of directly updating the Lucene index during my method DataService.save(data) I just create a new eventLogEntry with JPA using the same transcation.

@Stateless
@LocalBean
public class DataService {
    ....

    public Data save(Data myData)  {
        // JPA work....
        ...
        // Write a JPA eventLog entry indicating to update Lucene index
        ....
    }
    ....
} 

Now whenever a client calls the lucene search method, I run a flush method to update my lucene index based on the event log entries:

@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void flush() {
    Query q = manager.createQuery("SELECT eventLog FROM EventLog AS eventLog" );
    Collection<EventLog> result = q.getResultList();
    if (result != null && result.size() > 0) {

        for (EventLog eventLogEntry : result) {
            .... update lucen index for each entry
            .......
            // remove the eventLogEntry.
            manager.remove(eventLogEntry);
        }
    }
}

With the annotation TransactionAttributeType.REQUIRES_NEW the flush() method will only read already committed eventLog entries.

So a client will only see committed updates in the Lucene Index. Even during a transaction from one of my BusinessService-EJBs the lucene will not include 'unflushed' documents. This behavior is equals to the transaction model 'Read Committed'.

See also the similar discussion at: How making stateless session beans transaction-aware?

这篇关于如何对EJB3事务提交或回滚做出反应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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