首页 > 解决方案 > Spring数据cassandra中的生命周期事件onBeforeSave是否存在错误?

问题描述

让我们从文档开始: https ://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.mapping-usage.events

我已经按照描述实现了这个生命周期事件,以便在持久化之前对实体进行一些修改。

发布的代码是我无法发布的真实代码的简化,但这应该更好地解释这种情况。(真实的通过java反射做set部分,但是打印出来的结果是一样的)

    @Override
    public void onBeforeSave(BeforeSaveEvent<Person> event) {
        super.onBeforeSave(event);
        System.out.println("onBeforeSave");
        System.out.println(event.getStatement());
        System.out.println(event.getSource());

        event.getSource().setName("Edited");
        System.out.println("after setName");
        System.out.println(event.getStatement());
        System.out.println(event.getSource());
    }

    @Override
    public void onAfterSave(AfterSaveEvent<Person> event) {
        super.onAfterSave(event);
        System.out.println("onAfterSave");
        System.out.println(event.getSource());
    }

Person定义如下:

public class Person {
    private String name;

    // default getter, setter and constructor....
}

在我尝试保留此人的运行中,此代码导致

onBeforeSave
INSERT INTO person (name) VALUES ('Original');
Person{name: "Original"}

after setName
INSERT INTO person (name) VALUES ('Original');
Person{name: "Edited"}

onAfterSave
Person{name: "Edited"}

传入的实体onBeforeSave已正确传递给onAfterSave方法,因此如果我在第一个中进行一些更改,它将传递给第二个。底层查询和持久化值是调用之前的实体值onBeforeSave,因此如果方法中的实体发生某些更改onBeforeSave,这些将不会被持久化,并且底层查询在执行前不会更新。

查看 https://github.com/spring-projects/spring-data-cassandra/blob/main/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java

在方法executeSave中,回调调用的返回值(更新后的值entityToSave)不会在下一行传递doExecute。这将运行上一个查询。我不知道这是否是一种期望的行为,但我认为一开始链接的wiki中的一个或者这个实现是错误的。

我也尝试编辑语句,但我找不到在方法中操作其映射值的onBeforeSave方法。有没有办法做到这一点?

我是唯一一个发现这个问题的人吗?我找不到关于此的任何问题,此时我真的需要onBeforeSave它将按照文档中的描述工作(能够在持久化之前修改实体)。

编辑 2021-06-01:

现在,我在编写自己的CassandraTemplate实现时取得了不错的成绩。我分享结果代码。它没有经过优化(它在每次编辑后多次运行查询生成功能,但它似乎按预期工作)

private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, Function<T, Statement> fz,
            Consumer<WriteResult> resultConsumer) {

        maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, fz.apply(entity)));
        T entityToSave = maybeCallBeforeSave(entity, tableName, fz.apply(entity));

        WriteResult result = getCqlOperations().execute(new StatementCallback(fz.apply(entityToSave)));
        resultConsumer.accept(result);

        maybeEmitEvent(new AfterSaveEvent<>(entityToSave, tableName));

        return EntityWriteResult.of(result, entityToSave);
    }

在此代码fz中表示查询生成功能。之前的这一代是在原始类的其他部分完成的,并且将语句传递给该方法。我改为传递函数本身,因此该方法可以在onBeforeSave.

希望这会有所帮助。

标签: javaspringcassandraspring-data-cassandra

解决方案


推荐阅读