我已经将服务实现为无状态会话 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 表单 stateless 更改为 statefull 会对性能产生影响。
或者有没有其他方法可以解决这个问题?例如,一个监听器根据事务 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 具有事务意识?