概述

变更日志提供了一种内置机制,用于记录变更(插入、更新和删除事件)。有 4 个接口,我们可以选择性地实现它们来控制机制的各个部分。默认情况下,我们可以使用 @ChangeLog 注释实体 Bean,并将变更以 JSON 格式记录到日志记录器中。

@History 有重叠,后者是一种以数据库为中心的方法。与 @ChangeLog 不同,@History 是事务性的,并且不能被绕过。

注意事项

SqlUpdate、CallableSql 和通过 Update 进行的批量更新不包含在变更日志中。

入门

步骤 1:确定插入的默认值

插入可以默认包含在变更日志中或不包含,这取决于应用程序。在使用 @ChangeLog 注释实体 Bean 时最好先考虑这一点,因为我们可以选择覆盖默认行为。

默认情况下,插入会被包含。DatabaseConfig.setChangeLogIncludeInserts(boolean) 可用于控制默认行为。这也可以通过 application.properties 设置。

ebean.changeLogIncludeInserts=false

步骤 2:添加 @ChangeLog

@ChangeLog 注释添加到应启用变更日志记录的所有实体 Bean。

@ChangeLog
@Entity
public class Address {
...

/**
 * Only include updates if specific properties are changed.
 */
@ChangeLog(updatesThatInclude = {"name","dateOfBirth"})
@Entity
public class Customer {
...


/**
 * Override the default behaviour for inserts - INCLUDE, EXCLUDE or DEFAULT.
 * In this case exclude inserts from the change log.
 */
@ChangeLog(inserts = ChangeLogInsertMode.EXCLUDE)
@Entity
public class Customer {
...

步骤 3:实现 ChangeLogPrepare

如果我们跳过此步骤并且不提供 ChangeLogPrepare 实现,则会使用“无操作”实现,并且用户上下文信息(用户 ID、用户 IP 地址等)将保持未填充状态。

通常,我们实现 ChangeLogPrepare,获取用户上下文信息(如用户 ID 和用户 IP 地址),并将其设置在变更集中。返回 true 表示处理继续,并且变更集在后台线程中传递给 ChangeLogListener。

如果我们希望在前景中进行日志记录,则可以在准备方法中调用日志记录并返回 false(这意味着变更集不会在后台线程中传递给 ChangeLogListener)。

class MyChangeLogPrepare implements ChangeLogPrepare {

  @Override
  public boolean prepare(ChangeSet changes) {

    // get user context information typically from a
    // ThreadLocal or similar mechanism

    String currentUserId = ...;
    changes.setUserId(currentUserId);

    String userIpAddress = ...;
    changes.setUserIpAddress(userIpAddress);

    changes.setSource("myApplicationName");

    // add arbitrary user context information to the
    // userContext map
    changes.getUserContext().put("some", "thing");

    return true;
  }
}

步骤 4:注册 ChangeLogPrepare 实现

如果启用了类路径扫描,则可以自动检测 ChangeLogPrepare 的实现(就像找到实体 bean 一样)。也就是说,如果启用了扫描,则我们不需要显式注册 ChangeLogPrepare 实现,而是会找到并实例化它。

如果未使用扫描或 ChangeLogPrepare 实现具有依赖项,并且其实例化应在 Ebean 外部执行,那么我们使用 DatabaseConfig 显式注册它。

// example code explicitly registering the ChangeLogPrepare implementation

MyChangeLogPrepare changeLogPrepare = ...;

DatabaseConfig config = new DatabaseConfig();
...
// register explicitly here
config.setChangeLogPrepare(changeLogPrepare);


Database database = DatabaseFactory.create(config);
...

步骤 5:配置日志记录

ChangeLogListener 的默认实现将事件记录到 io.ebean.ChangeLog。通常,我们会配置日志记录,以便这些日志转到一个单独的日志。

在下面的 logback xml 配置中,追加器 CHANGE_LOG 用于将更改事件记录到此单独的日志。

<appender name="CHANGE_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <File>log/changeLog.log</File>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <FileNamePattern>log/changeLog.log.%d{yyyy-MM-dd}</FileNamePattern>
    <MaxHistory>90</MaxHistory>
  </rollingPolicy>
  <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <pattern>%d{HH:mm:ss.SSS} %msg%n</pattern>
  </encoder>
</appender>

<logger name="io.ebean.ChangeLog" level="TRACE" additivity="false">
  <appender-ref ref="CHANGE_LOG"/>
</logger>