为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

米琪卡哇伊 2021-08-04 10:17:18
我已将服务实现为无状态会话 EJB (3.2) 以通过 JPA 存储数据。此外,每次更新数据时,EJB 也会更新一个 Lucene 索引。会话 bean 是容器管理的。ejb 的代码如下所示:@Stateless@LocalBeanpublic class DataService {    ....    public Data save(Data myData)  {        // JPA work....        ...        // update Lucene index        ....    }    ....} 我有不同的其他 BusinessService-EJB 调用这个 DataService EJB 来插入或更新数据。我无法控制 BusinessService-EJB 实现。由 BusinessService-ejb 启动的事务可以包含对 DataService EJB 的 save() 方法的多次调用。@Stateless@LocalBeanpublic 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 索引......?
查看完整描述

2 回答

?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

如果 lucene 索引不是事务性的,您将无法在发生故障时回滚。

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

如果索引更新失败了怎么办?

整个事情必须在单个事务中,并且只有在其中的每个操作都成功时才必须提交该事务。这是保证数据一致性的唯一方法。

编写一些测试来检查当您使用 @Transactional 或使用 UserTransaction 注释调用方方法时事务的反应。


查看完整回答
反对 回复 2021-08-04
?
手掌心

TA贡献1942条经验 获得超3个赞

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


而不是在我的方法 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 搜索方法时,我都会运行一个刷新方法来根据事件日志条目更新我的 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 也不会包含“未刷新”的文档。此行为等同于事务模型“已提交读”。


查看完整回答
反对 回复 2021-08-04
  • 2 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信