是否存在一些更好的方式来记录更新历史记录?

Does exist some better manner to logger update history?

在我们的后端系统中,有很多情况需要更新对象,例如更新商品,更新商品价格,更新用户,更新状态,更新订单(取消,更新价格)等。现在一些对象我们有一个特殊的日志 table,例如order_update_log ,记录器更新操作。有些只记录器到文件,例如

logger.info("goods update: before: {}, after: {}", oldGoods, newGoods)

感觉处理这些琐碎的事情很烦人,有没有更好的manner/tools这样处理logger?

如果您使用 ORM 来保存数据,您可以使用 Hibernate 的 Listners/events 之类的东西来响应数据更新(并将它们记录到数据库或审计日志等) 对于休眠,这里有详细信息:https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html 但显然您需要调查您的持久性工具是否提供给您。

有一个非常好的东西叫做 Aspects。 您可以为您的项目编写只知道跟踪商品对象更改的方面。假设你有 Goods class:

public class Goods {
    private Integer id;
    private String name;
    private BigDecimal cost;

    // Getters, Setters
    ...
}

映射到数据库table商品对应字段:

CREATE TABLE `goods` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `name` varchar NOT NULL,
    `cost` DECIMAL NOT NULL,
    PRIMARY KEY (`id`)
);

假设你有 GoodsService:

public class GoodsService {

    public Goods read(Integer id) {
        Goods goods = /* Read goods from database */
        return goods;
    }

    public void write(Goods goods) {
        /* Write goods to database */
    }
}

GoodsController 使用 GoodsService:

public class GoodsController {

    private GoodsService goodsService;

    public void updateGoods(Integer id, String name, BigDecimal cost) {
        Goods goods = goodsService.read(id);
        goods.setName(name);
        goods.setCost(cost);
        goodsService.write(goods);
    }

}

因此,让我们为您的项目添加一些魔法来跟踪货物的变化。现在创建另一个 table,其中包含用于存储更新 goods 对象的 userdatetime 的附加字段:

CREATE TABLE `goods_log` (
    `revision` INT NOT NULL AUTO_INCREMENT,
    `id` INT NOT NULL,
    `name` varchar NOT NULL,
    `cost` DECIMAL NOT NULL,
    `user` varchar NOT NULL,
    `timestamp` DATETIME NOT NULL,
    PRIMARY KEY (`revision`,`id`)
);

写方面class:

@Aspect
public class GoodsLogger {
    @Before(value = "execution(* org.antonu.service.GoodsService.write(..)) && args(goods)")
    public void logWrite(Goods goods) {
        // Get current user and timestamp,
        // Write it to goods_log table, as well as goods data
    }
}

就是这样!您的业​​务逻辑代码没有改变,阅读起来很清楚。但是每次调用 GoodsService 的 write 方法时,您都会在 goods_log 中获得带有新商品状态的记录。

要使此代码正常工作,应使用 AJC 编译器对其进行编译,还应包括 aspectjrt 库。它可以通过 maven 轻松完成:

<properties>
    <aspectj.version>1.8.7</aspectj.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

现代 IDE Intellij Idea 应该自动使用 AJC 编译器和上面的 maven 配置。如果没有,您必须通过 File - Settings - 'Build, Execution, Deployment' - Compiler - Java Compiler - Use compiler: Ajc. AJC 编译器路径配置编译器:<path_to>/aspectjtools-1.8.7.jar