有插入时的数据库轮询 - Spring Data JPA

Posted

技术标签:

【中文标题】有插入时的数据库轮询 - Spring Data JPA【英文标题】:Database polling when there's an insert - Spring Data JPA 【发布时间】:2021-10-26 06:08:47 【问题描述】:

我有一个要求,只要表中有条目,我就想触发一个事件。我为此使用了 EntityListeners(Spring Data JPA 概念),效果很好;但这里的问题是插入可以通过存储过程或手动输入发生。我尝试在网上搜索,发现 Spring JPA 入站和出站通道适配器概念,但我认为这个概念对我想要实现的目标没有多大帮助。任何人都可以向我澄清这个概念是否对我有帮助,因为我对这个概念没有太多想法,或者为我提供任何解决方案来解决这个问题?

【问题讨论】:

据我所知,您需要在数据库端进行处理。类似***.com/a/9556527/4762502 @GauravJeswani 感谢您的链接,但这也适用于 MS SQL Server 吗? mysql 可能有一些其他的触发器语法,但它们也有触发器。所以我相信,如果你读了一点,你也会得到 MySql 触发器语法,这对你有用。 【参考方案1】:

在 SQL Server 中没有“从数据层”引发事件的“出色”机制。

一共有三个“OK”:

    触发器(只能说可以)

触发器似乎是一个显而易见的解决方案,但你必须问自己......触发器实际上会做什么?如果它只是将数据写入另一个表,您仍然没有将自己置于数据库之外。您可以尝试使用各种神秘技巧,例如 CLR 过程或一些扩展过程。

但是如果你沿着这条路走,你必须开始考虑另一个考虑因素:触发器与导致它们触发的 DML 操作发生在同一个事务中。如果它们需要时间来执行,您将减慢 OLTP 工作负载。如果他们做了任何可能不可靠的事情,他们可能会失败,从而导致您的事务回滚。

    触发器加服务代理

Service Broker 提供了一种机制——也许是唯一一种半明智的机制——以基于“推送”的方式将您的数据从 SQL 中取出并进入某种侦听器。您仍然有一个触发器,但触发器将数据写入服务代理队列。侦听器可以使用特殊的waitfor receive 语句来侦听出现在队列中的数据。这样做的好处是,一旦触发器将数据推送到代理队列,它的工作就完成了。该数据的“收据”与最初导致其排队的事务分离。这种服务代理机制就是 dot net 中内置的 SqlDependency 之类的东西所使用的。

服务代理的两个主要问题是复杂性和性能。服务代理的学习曲线陡峭,很容易出错。如果您需要扩展,性能会变得复杂,因为虽然构建 xml 或 json 有效负载“很容易”,但基于大型集合的数据更改可能意味着这些有效负载非常庞大。

无论如何,如果你想探索这条路线,你会想要阅读Remus Rusanu关于该主题的(所有)优秀文章

请记住,这是一种异步“近实时”机制,而不是触发器等同步“实时”机制。

    轮询内置变更检测机制:CDC 或变更跟踪。

Sql server 带有两种技术,可以原生地“观察”表中发生的变化并记录它们:Change Tracking 和 Change Data Capture

这些都不是将数据推送到数据库之外,它们都是基于“拉取”的。他们所做的是在发生更改时将其他数据存储在数据库中。 CDC 可以提供每个更改的完整日志,而更改跟踪“指向”通过主键值更改的行。虽然这两个都涉及“投票历史”,但它们之间存在显着差异,因此请阅读细则。

请注意,CDC 是“双重异步”的——数据是从事务日志中读取的,因此记录数据不是原始事务的一部分。然后你必须轮询 CDC 数据,它不会推送给你。此外,当您启用 CDC 时,Microsoft 生成的功能可能会非常慢,只要您要求一些有用的东西,例如 net changes with mask(它可以告诉您哪些列真正改变了它们的值),并且您启用 CDC 的能力来了有很多警告和限制(同样,请阅读所有这些的文档)。

至于哪一个是“最好的”,那是见仁见智的问题。作为从 SQL 中获取事件的一种方式,我广泛使用了 CDC,很少使用服务代理,并且几乎从不使用触发器。我从未在生产环境中实际使用过变更跟踪,但如果我再次有选择,我可能会选择变更跟踪而不是变更数据捕获,至少直到或除非有要求强制使用 CDC,因为它的附加功能超出变更跟踪所能提供的功能。

最后一点:如果您需要“保证”引发的事件实际上已被侦听器收集并成功转发给订阅者,那么您还有一些工作要做!有保证的消息传递很难。

【讨论】:

感谢您的努力我在这里有一个疑问,如果使用 CDC 或 CT 在指定表中进行一些更新/插入,我们是否能够从中间件方面了解? 是的,但是您必须根据某种计时机制来轮询数据。这两种机制都不会将事件“推送”到客户端,您必须定期检查以查看是否有新的更改可用。但是这两种机制都提供了一种确定更改是否“新”的方法。为此,客户端会存储一个“高水位线”值,以指示客户端在更改日志方面的进度。

以上是关于有插入时的数据库轮询 - Spring Data JPA的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA - 手动插入后的密钥冲突

Spring Data JPA + Postgres - 无法使用一对一映射插入数据

Spring Data JPA:嵌套实体的批量插入

使用日期参数时的 Spring Data JPA 日期“之间”查询问题

集成 Spring JPA Data 和 Spring Cache 时的奇怪行为

spring data jpa使用spring data jpa时,关于service层一个方法中进行删除和插入两种操作在同一个事务内处理