如何对 EJB3 事务提交或回滚做出反应?

我已将服务实现为无状态会话 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 工作将按预期回滚(没有数据写入数据库)。但是现在 Lucene 索引已经在事务被取消之前为 save() 方法的所有成功完整调用更新。


所以我的问题是:我如何对我的 DataService EJB 中的这种情况做出反应?这甚至可能吗?


我看到使用 Statefull Session EJB 3.2 我可以使用注释“ @AfterCompletion”来注释方法。因此,我想这可能是仅当 @AfterCompletion 以“成功”调用时才编写 lucene 索引的解决方案。但是这个注释对于无状态会话 EJB 是不允许的。我应该简单地将我的 EJB 类型从无状态更改为有状态吗?但这对我的 BusinessService-EJB 场景有何影响,它仍然是一个无状态会话 EJB?这行得通吗?我还担心将我的 ejb 形式无状态更改为有状态会对性能产生影响。


或者有没有其他方法可以解决这个问题?例如,监听器根据事务 ID 写入日志,并在事务完全完成后更新 lucene 索引......?


米琪卡哇伊
浏览 122回答 2
2回答

有只小跳蛙

如果 lucene 索引不是事务性的,您将无法在发生故障时回滚。或者有没有其他方法可以解决这个问题?例如,监听器根据事务 ID 写入日志,并在事务完全完成后更新 lucene 索引......?如果索引更新失败了怎么办?整个事情必须在单个事务中,并且只有在其中的每个操作都成功时才必须提交该事务。这是保证数据一致性的唯一方法。编写一些测试来检查当您使用 @Transactional 或使用 UserTransaction 注释调用方方法时事务的反应。

手掌心

我通过以下方式解决了这个问题:而不是在我的方法 DataService.save(data) 期间直接更新 Lucene 索引,我只是使用相同的事务使用 JPA 创建一个新的 eventLogEntry。@Stateless@LocalBeanpublic class DataService {&nbsp; &nbsp; ....&nbsp; &nbsp; public Data save(Data myData)&nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // JPA work....&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; // Write a JPA eventLog entry indicating to update Lucene index&nbsp; &nbsp; &nbsp; &nbsp; ....&nbsp; &nbsp; }&nbsp; &nbsp; ....}&nbsp;现在,每当客户端调用 lucene 搜索方法时,我都会运行一个刷新方法来根据事件日志条目更新我的 lucene 索引:@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)public void flush() {&nbsp; &nbsp; Query q = manager.createQuery("SELECT eventLog FROM EventLog AS eventLog" );&nbsp; &nbsp; Collection<EventLog> result = q.getResultList();&nbsp; &nbsp; if (result != null && result.size() > 0) {&nbsp; &nbsp; &nbsp; &nbsp; for (EventLog eventLogEntry : result) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .... update lucen index for each entry&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .......&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // remove the eventLogEntry.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; manager.remove(eventLogEntry);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}有了注解TransactionAttributeType.REQUIRES_NEW,flush() 方法将只读取已经提交的 eventLog 条目。因此,客户端只会在 Lucene 索引中看到已提交的更新。即使在来自我的一个 BusinessService-EJB 的事务期间,lucene 也不会包含“未刷新”的文档。此行为等同于事务模型“已提交读”。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java