如何将实体的更改记录到日志文件中?
考虑我有Person
这样的人。
import org.hibernate.envers.Audited;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
@Entity
@Audited
public class Person {
@Id
@GeneratedValue
private int id;
private String name;
private String surname;
// add getters, setters, constructors, equals and hashCode here
}
以及更改现有Person
Person p1 = new Person("name-1", "surname-1");
personRepository.save(p1);
Person p2 = personRepository.findOne(1L);
p2.setName("new-name");
personRepository.save(p2);
我怎么有
在我的日志文件中?我知道envars可以存储在数据库的变化,让我用AuditReader
后提取出来,但我喜欢用JSON文件存储更改它们发送到第三方应用程序(如弹性)。
答案 0 :(得分:1)
我实际上将从两个角度解决这个问题。
使用Envers可以带来的好处之一是,您可以非常快速地注释实体,并准确地告诉框架您希望如何跟踪实体模型的更改。更好的是,您可以让Envers自动为您生成可扩散字段。
让我们接受这个基本实体:
@Entity
@Audited(withModifiedFlag = true)
public class Person {
@Id
@GeneratedValue
private Integer id;
private String name;
}
启用withModifiedFlag
功能后,这会通知Envers为该实体的审核表添加一些其他元数据列,因此,基本上该实体的审核表将如下所示:
+----+------+----------+-----+---------+
| ID | name | name_MOD | REV | REVTYPE |
+----+------+----------+-----+---------+
这样做的好处是,如果您正在使用某种过程直接从表中导出数据并流式传输数据,则不再需要实际将当前行与先前行进行区分以了解发生了什么变化;该架构仅通过查看关联的_MOD
列是1
(是)(是)还是0
(否)(是)就可以自动告诉您。
从这一点上来说,您有两种选择。
您可以使用Hibernate本机查询通过某些后台应用程序线程或单独的后台进程将数据提取并将其转换为ES的JSON。由于_MOD
列为您提供了字段更改的指示符,因此您可以轻松读取行并构建必要的数据,而不必在提取时执行diff操作。
我还建议配置Envers,以将审核对象放置在单独的目录/架构中。这样可以最大限度地提高数据库同时改善多个数据库中磁盘IO的能力。
Debezium项目是处理数据复制的绝佳方法。其强大的优势之一是,它使用户能够跨各种平台进行此操作,而这些平台恰好适合您的模型。
此处的最大区别是Debezium不会直接读取数据库来确定更改,而是读取数据库事务日志文件并生成一系列事件,这些事件描述了针对该数据库进行的DML操作。简而言之,由于Debezium直接从事务日志中重新补充了状态,因此避免了担心的读取操作。
例如:
INSERT INTO Person (?,?) VALUES (?,?)
。INSERT INTO Person_AUD (...) VALUES (....)
Person_AUD
(已预订的表)生成一个插入事件。在(5)中,将存在您的转换/加载代码以接收该插入事件并生成JSON输出并将其发送给ES。
通过使用Debezium,您可以在非常高效的庄园中有效地 offline 在异构环境中复制数据。该项目不仅适合您的用例,而且在当今微服务体系结构中至关重要,在当今的微服务体系结构中,服务之间的数据共享至关重要。
通过使用Envers,您能够提供在线后备解决方案,以便在ES群集不可用或过载时为用户提供审核历史数据的功能,而不是为用户提供“服务不可用,稍后再返回”响应。
无论您决定什么,性能都不是唯一相关的因素。您还应该注意用户体验,可伸缩性和可靠性。因此,为什么我认为最佳的解决方案是将两者配对。
答案 1 :(得分:0)
您可以通过实现org.hibernate.EmptyInterceptor
来编写自定义拦截器。它具有使用实体的旧快照和新快照更新/插入/删除的回调。
有关更多详细信息,请参见this文章