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

问题描述 投票:0回答:2

我已经将服务实现为无状态会话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”注释一个方法。所以我想这可能只是在用'成功'调用@AfterCompletion时编写lucene索引的解决方案。但是无状态会话EJB不允许使用此注释。我应该简单地将EJB类型从无状态更改为有状态吗?但是,这对使用仍然是无状态会话EJB的BusinessService-EJB影响我的场景有何影响?这会有用吗?我还担心将我的ejb形式无状态改为有状态会对性能产生影响。

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


2018-08-29 - 解决方案:

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

我没有在我的方法DataService.save(data)中直接更新Lucene索引,而是使用相同的transcation创建一个带有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也不会包含“未刷新的”文档。此行为等于事务模型“Read Committed”。

另见类似的讨论:How making stateless session beans transaction-aware?

java transactions rollback ejb-3.2
2个回答
0
投票

如果lucene index不是transactionnal,则在发生故障时将无法回滚。

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

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

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

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


0
投票

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

我没有在我的方法DataService.save(data)中直接更新Lucene索引,而是使用相同的transcation创建一个带有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也不会包含“未刷新的”文档。此行为等于事务模型“Read Committed”。

另见类似的讨论:How making stateless session beans transaction-aware?

© www.soinside.com 2019 - 2024. All rights reserved.