使用 JaVers 进行异步审计
Async auditing with JaVers
我需要审核对我们应用程序中某些实体的更改,并且正在考虑使用 JaVers。我喜欢 JaVers 提供的对查询审计数据的支持。 Hibernate Envers 看起来不错,但它把数据存储在同一个数据库中。
这是我的要求:
- 异步日志记录 - 对性能的影响最小
- 将审计数据存储在不同的数据库中 - 性能原因也是如此
据我所知,JaVers 并不是为上述目的而设计的,但似乎可以适应以实现上述目的。方法如下:
- JaVers 实际上允许将数据存储在不同的数据库中。您实际上可以提供与任何数据库的连接。这不是它的意图,但它有效。下面的代码(注意 connectionProvider 可以提供到任何数据库的连接):
'
final Connection dbConnection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/javers", "root", "root");
ConnectionProvider connectionProvider = new ConnectionProvider() {
@Override
public Connection getConnection() {
//suitable only for testing!
return dbConnection;
}
};
JaversSqlRepository sqlRepository = SqlRepositoryBuilder
.sqlRepository()
.withConnectionProvider(connectionProvider)
.withDialect(DialectName.MYSQL).build();
- 可以通过将 JaVers 提交的执行移动到 thread/executor 来实现异步。这样做的挑战在于,如果执行时间太长,则可能是对象在记录之前发生了更改。我在这里可以想到两种解决方案:
- 我们可以创建对象的快照(例如将其序列化为 JSON 等)并将其传递给线程以记录它。
- 我们提供 Javers Repository 的自定义实现,它处理当前线程中的差异,然后传递快照对象以在另一个线程中持久化。这样我们就只会在应用程序线程中从数据库中读取,并在审计线程中进行写入(这通常在性能方面成本更高)。
问题:
- 我在这里遗漏了什么吗?这行得通吗?
- JaVers 是否支持创建对象的快照,然后可以将其移动到另一个线程。它在内部某处进行,所以也许我们可以使用它。
仅供参考:与问题无关,但这里有一些我能想到的其他挑战以及我打算如何解决它们:
- 由于不在同一事务中进行审计,就好像事务失败一样,这会使审计回滚变得复杂。所以我们只需要审计成功提交的对象。我打算通过使用 Hibernate 拦截器来做到这一点,监听
afterTransactionCompletion
并且只提交由该事务更新的对象。
- 在延迟加载对象的情况下,我可以看到,如果我们在事务完成后尝试访问它们,可能是无法访问延迟加载的道具(因为会话可能是closed too) - 不知道如何解决这个问题,但这可能不是问题,因为我认为我们正在加载大多数道具。
有趣的问题。
首先是德门蒂人。所有 JaVers 核心模块都旨在将审计数据与应用程序数据分离。正如您提到的,用户提供了一个供 JaVers 使用的 ConnectionProvider。它可以是您想要的任何数据库。
SQL 的 Spring 集成模块并非设计用于多个数据库,因此 javers-spring-jpa
和 javers-spring-boot-starter-sql
。它们只涵盖最常见的场景,因此应用程序和 JaVers 的数据库相同。
关于缺少异步提交,你是对的。幸运的是,它可以只在 JaversCore
中实现,而无需更改 Repositories。
API 可能是:
CompletableFuture<Commit> javers.commitAsync(..., Executor);
首先,Javers 会对用户的对象进行快照,速度很快,因此可以在当前线程中完成。
然后,数据库读取(加载最新快照)和数据库写入(插入新快照)可以异步完成(提交给给定的执行器)。
正如您所提到的,它需要新的数据库事务处理方法。我们计划实现 Commit Withdrawal 功能,这样应用程序就可以在主数据库回滚后撤回 JaVers 的提交。参见 https://github.com/javers/javers/issues/588
我需要审核对我们应用程序中某些实体的更改,并且正在考虑使用 JaVers。我喜欢 JaVers 提供的对查询审计数据的支持。 Hibernate Envers 看起来不错,但它把数据存储在同一个数据库中。
这是我的要求:
- 异步日志记录 - 对性能的影响最小
- 将审计数据存储在不同的数据库中 - 性能原因也是如此
据我所知,JaVers 并不是为上述目的而设计的,但似乎可以适应以实现上述目的。方法如下:
- JaVers 实际上允许将数据存储在不同的数据库中。您实际上可以提供与任何数据库的连接。这不是它的意图,但它有效。下面的代码(注意 connectionProvider 可以提供到任何数据库的连接):
'
final Connection dbConnection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/javers", "root", "root");
ConnectionProvider connectionProvider = new ConnectionProvider() {
@Override
public Connection getConnection() {
//suitable only for testing!
return dbConnection;
}
};
JaversSqlRepository sqlRepository = SqlRepositoryBuilder
.sqlRepository()
.withConnectionProvider(connectionProvider)
.withDialect(DialectName.MYSQL).build();
- 可以通过将 JaVers 提交的执行移动到 thread/executor 来实现异步。这样做的挑战在于,如果执行时间太长,则可能是对象在记录之前发生了更改。我在这里可以想到两种解决方案:
- 我们可以创建对象的快照(例如将其序列化为 JSON 等)并将其传递给线程以记录它。
- 我们提供 Javers Repository 的自定义实现,它处理当前线程中的差异,然后传递快照对象以在另一个线程中持久化。这样我们就只会在应用程序线程中从数据库中读取,并在审计线程中进行写入(这通常在性能方面成本更高)。
问题:
- 我在这里遗漏了什么吗?这行得通吗?
- JaVers 是否支持创建对象的快照,然后可以将其移动到另一个线程。它在内部某处进行,所以也许我们可以使用它。
仅供参考:与问题无关,但这里有一些我能想到的其他挑战以及我打算如何解决它们:
- 由于不在同一事务中进行审计,就好像事务失败一样,这会使审计回滚变得复杂。所以我们只需要审计成功提交的对象。我打算通过使用 Hibernate 拦截器来做到这一点,监听
afterTransactionCompletion
并且只提交由该事务更新的对象。 - 在延迟加载对象的情况下,我可以看到,如果我们在事务完成后尝试访问它们,可能是无法访问延迟加载的道具(因为会话可能是closed too) - 不知道如何解决这个问题,但这可能不是问题,因为我认为我们正在加载大多数道具。
有趣的问题。 首先是德门蒂人。所有 JaVers 核心模块都旨在将审计数据与应用程序数据分离。正如您提到的,用户提供了一个供 JaVers 使用的 ConnectionProvider。它可以是您想要的任何数据库。
SQL 的 Spring 集成模块并非设计用于多个数据库,因此 javers-spring-jpa
和 javers-spring-boot-starter-sql
。它们只涵盖最常见的场景,因此应用程序和 JaVers 的数据库相同。
关于缺少异步提交,你是对的。幸运的是,它可以只在 JaversCore
中实现,而无需更改 Repositories。
API 可能是:
CompletableFuture<Commit> javers.commitAsync(..., Executor);
首先,Javers 会对用户的对象进行快照,速度很快,因此可以在当前线程中完成。
然后,数据库读取(加载最新快照)和数据库写入(插入新快照)可以异步完成(提交给给定的执行器)。
正如您所提到的,它需要新的数据库事务处理方法。我们计划实现 Commit Withdrawal 功能,这样应用程序就可以在主数据库回滚后撤回 JaVers 的提交。参见 https://github.com/javers/javers/issues/588