Hibernate OGM 已不再维护

Hibernate/JPA 的一个基本原则是,通过Session/EntityManagerAPI执行的任何写入操作都会收集到 持久化上下文 中,并且只有当事务提交时才会写入到数据库。如果需要,可以通过显式调用flush()方法来强制刷新更改。Hibernate 也可能在执行查询之前自动触发刷新。这种策略可以执行许多优化,例如,仅持久化实体多次更改后的最终状态,使用批量插入等。

Hibernate OGM 采用这种方法,并使用事务边界来标识工作单元并触发对数据存储的写入。当然,这在事务性NoSQL存储(如Infinispan或Neo4j)上运行得很好,但在没有完整事务语义的存储上会带来一些挑战。

例如,考虑一个无状态EJB的方法(该方法自动在容器管理的事务中运行)插入三个实体。如果在插入最后一个实体时发生错误,其他两个实体已经被写入。当使用非事务性数据存储时,无法回滚这些已应用更改。根据具体用例,这可能可以接受;但在其他情况下,可能希望采取某些操作,例如重试失败的插入或为成功的插入执行补偿写入,从而实际上撤销它们。

这正是我们新的 错误处理API 发挥作用的地方。它允许你在数据存储操作失败或事务回滚尝试时获得通知,并提供已执行和失败的运算(操作)。例如,这允许你

  • 记录所有应用的运算
  • 重试失败的运算(例如,在超时后)
  • 尝试补偿应用的更改(通过执行逆运算)

一个示例错误处理器

让我们看看一个例子

public class ExampleErrorHandler implements ErrorHandler {

    @Override
    public void onRollback(RollbackContext context) {
        // write all applied operations to a log file
        for ( GridDialectOperation appliedOperation : context.getAppliedGridDialectOperations() ) {
            switch ( appliedOperation.getType() ) {
                case INSERT_TUPLE:
                    EntityKeyMetadata entityKeyMetadata = appliedOperation.as( InsertTuple.class ).getEntityKeyMetadata();
                    Tuple tuple = appliedOperation.as( InsertTuple.class ).getTuple();

                    // write EKM and tuple to log file...
                    break;
                case REMOVE_TUPLE:
                    // ...
                    break;
                case ...
                    // ...
                    break;
            }
        }
    }

    @Override
    public ErrorHandlingStrategy onFailedGridDialectOperation(FailedGridDialectOperationContext context) {
        // Ignore this exception and continue
        if ( context.getException() instanceof TupleAlreadyExistsException ) {
            GridDialectOperation failedOperation = context.getFailedOperation();
            // write to log ...

            return ErrorHandlingStrategy.CONTINUE;
        }
        // But abort on all others
        else {
            return ErrorHandlingStrategy.ABORT;
        }
    }
}

TheonRollback()方法 - 当事务(或工作单元)回滚时(无论是用户还是容器触发的) - 展示了如何在回滚尝试之前迭代所有数据存储操作,检查它们的特定类型,例如将它们写入日志文件。

TheonFailedGridDialectOperation()该方法为每次具体的数据存储操作失败而调用。它允许您决定是继续 - 忽略失败 - 还是终止操作。如果ABORT被返回,将重新抛出导致异常,最终导致当前事务回滚。如果CONTINUE被返回,则忽略该异常,导致当前事务继续。

是否终止或继续的决定可以基于特定的异常类型或导致失败的网络网格操作。在示例中,所有类型为TupleAlreadyExistsException的异常都被忽略(意味着我们不在乎重复记录被插入到数据存储中),而所有其他异常都会导致当前工作单元被终止。您还可以根据需要对特定于数据存储的异常做出反应,例如MongoDB的MongoTimeoutException

创建ErrorHandler实现后,需要将其注册到Hibernate OGM。您可以通过在META-INF/persistence.xml中的持久化单元属性来完成此操作。

<property name="hibernate.ogm.error_handler" value="com.example.ExampleErrorHandler"/>

需要反馈!

在当前形式下,API为手动执行诸如重试、记录和类似任务奠定了基础。但我们设想在未来版本中采用更自动化的方法,例如自动重试失败的操作。

当然,此API无法也不会为不原生支持事务的数据存储提供事务保证。如果您发现自己经常处于希望进行“全或无”事务语义的情况,您可能需要考虑迁移到真正提供此功能的数据存储。但您也可以考虑更合适的映射方法。例如,可嵌入和元素集合是将实体及其依赖结构确保为原子性的好方法,例如MongoDB或CouchDB上的文档存储,因为它们将被映射为单个、层次结构的文档,可以通过单个数据存储调用进行更新。

目前,该API被认为是实验性的,将在未来的版本中发展。为此,您的反馈对我们非常重要!请告诉我们您想用这样的API做什么以及应该添加哪些功能。只需向@Hibernate发送推文或向我们开发列表发送邮件。如果您愿意,还可以对针对API进一步开发的JIRA问题添加评论:OGM-775(“引入RETRY错误处理策略”),OGM-776(“提供执行补偿操作的手段”)和OGM-777(“通过错误处理程序上下文公开更多上下文信息”)。

任何反馈都备受赞赏!


返回顶部