【问题标题】:Capture generated SQL from Hibernate从 Hibernate 捕获生成的 SQL
【发布时间】:2018-08-16 15:54:20
【问题描述】:

我需要捕获对某些数据的更改。我希望捕获以下详细信息:

  1. 表名称发生更改
  2. 列已更改
  3. 以前的值
  4. 更新值

我向我们的技术主管建议,这可以通过 DB 触发器轻松完成。有人告诉我,我们无法控制数据库,也无法添加触发器。

我目前正在使用带有自定义注释的 Spring AspectJ 并包装我的服务以尝试捕获在调用“保存”方法后执行的生成的 SQL(我认为解析 SQL 比尝试使用对象捕获要容易得多),但是我还没有找到捕获生成的 SQL 的方法。

我尝试了 p6Spy 并且能够查看 SQL 并将其打印到控制台,但被告知我们不能将我们的数据库驱动程序包装在我们的 PROD 环境中。

我是否缺少一个 Spring 类来简化此操作?

编辑:我们使用 Spring Repositories 来保存数据。

编辑 2:我正在调查 EventListeners,但我似乎无法让他们收听我的活动。

@Component
public class EventListner implements PreInserEventListener, PreUpdateEventListener {
   @Override
   @EventListener
   public boolean onPreUpdate(PreUpdateEvent event){
     // do something

     return false;
   }

   @Override
   @EventListener
   public boolean onPreInsert(PreUpdateEvent event){
     // do something
   }
   return false
}

我的Listener 周围有断点,但它们从未到达过。


This question 看起来可以解决我的问题

【问题讨论】:

  • 我正在调查@EventListeners,看看是否可以捕获那里的值。
  • 如果你不想使用envers,那么你可以fork envers项目来将数据推送到你想要的地方。不确定它是简单还是复杂,但过程在那里(过滤,旧值,新值),我猜是正确的。 (1个实体可以手动备份,100个参数化,不是真的)
  • 是的,我们有可能“审核”1000 个实体
  • 您将更改存储在哪里?拦截 SQL 也无济于事。另外你为什么不控制数据库?在编写应用程序时如何管理表更改。
  • 计划解析 INSERT 和 UPDATE 语句并将它们保存在我们的审计表中。我们没有控制 b/c,它是一项托管服务,因此触发器会对其他应用程序产生副作用。

标签: java spring hibernate


【解决方案1】:

如果您绝对确定每次插入/更新/删除都是通过 JPA 完成的,没有任何批量 SQL,那么您应该看看 envers

您可以在实体(所有列)或您希望保留历史记录的实体列上使用@Audited

这将创建 1 个带有时间戳更改的修订表(以及您想要的其他数据,例如进行更改的用户的 uid),并为每个实体创建 1 个具有修改数据旧值的表。

然后,您可以检索每个数据的历史记录和以前的值。

另一种方法是在您的数据库中添加工具,例如更改数据捕获 (CDC) 工具,并将这些事件推送到另一个数据存储库。 在 + 方面,一切都会被检测到(甚至本地 SQL 直接在数据库上运行)。缺点,您的数据库需要正确支持这种工具。例如,kafka-connect 之类的工具可以按您的意愿工作,但有些实现过于简单(例如使用 SAP hana,流程要执行select * from xxx)。

【讨论】:

  • 我们对此进行了调查,但是为我们正在审核的每个表创建影子并不是我们的管理层想要做的事情。
【解决方案2】:

我最终决定使用 Hibernate 拦截器来解决问题。完美运行!

public class TableInterceptor extends EmptyInterceptor {

   @Override
   public boolean onFlushDirty(Object entity, Serializable id,
                               Object[] currentState, Object[] previousState,
                               String[] propertyNames, Type[] types){

         // do comparison logic on fields and save to DB
   }
}

我引导拦截器将其注入我的LocalContainerEntityManagerFactoryBean

【讨论】:

    猜你喜欢
    • 2014-07-02
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 2011-04-26
    • 1970-01-01
    • 2011-01-27
    相关资源
    最近更新 更多