“Where query”在生产环境中创建错误的 SQL

Posted

技术标签:

【中文标题】“Where query”在生产环境中创建错误的 SQL【英文标题】:"Where query" creates wrong SQL on production 【发布时间】:2016-05-10 06:21:53 【问题描述】:

我不得不将 Spring 从 1.2.7 更新到 2.0,以及将 Grails 从 2.2.0 更新到 2.3.11。在解决了一些典型的更新问题后,我开始为测试服务器构建一个 WAR。一切似乎都很好。但经过几次部署后,我遇到了问题。

有时(没有规则)服务器有 100% CPU 使用率 -> OutOfMemeryError 或应用程序抛出错误 500。调试后发现这些问题的原因是 SQL 查询不正确。

哪里查询:

UserRole.findrole.authority =~ "%$authTxt" && user.id == currentUser.id

创建这样的 SQL:

select this_.id as id1_35_2_, this_.payment_enabled as payment_2_35_2_, this_.role_id as role_id3_35_2_, this_.user_id as user_id4_35_2_,
role_alias1_.id as id1_29_0_, role_alias1_.version as version2_29_0_, role_alias1_.authority as authorit3_29_0_, user_alias2_.id as id1_36_1_,
user_alias2_.version as version2_36_1_, user_alias2_.account_expired as account_3_36_1_, user_alias2_.account_locked as account_4_36_1_, 
user_alias2_.auto_password_flag as auto_pas5_36_1_, user_alias2_.email as email6_36_1_, user_alias2_.enabled as enabled7_36_1_, 
user_alias2_."password" as password8_36_1_, user_alias2_.password_expired as password9_36_1_, user_alias2_.user_info_id
as user_in10_36_1_, user_alias2_.username as usernam11_36_1_ from user_role this_ inner join role role_alias1_ on this_.role_id=role_alias1_.id inner join users user_alias2_ 
on this_.user_id=user_alias2_.id where (1=1 and 1=1)

这里是正确的 SQL:

... inner join role role_alias1_ on this_.role_id=role_alias1_.id inner join users user_alias2_ on this_.user_id=user_alias2_.id 
where ((role_alias1_.authority ilike ?) and (user_alias2_.id=?)) 

明显的问题是表达式 "(1 = 1 and 1 = 1)"。其实这样的查询:

User.findAll id == userid 

检索整个表。 动态查找器或标准不会导致此问题。

我找到了两个有类似问题的人:

https://zenofchicken.wordpress.com/2016/01/06/freaky-grails-where-clauses-dont-work-anymore/

http://grails.1312388.n4.nabble.com/Finder-not-applying-criteria-td4655689.html

我使用的插件:

spring-security-core:2.0-RC5 spring-security-oauth:2.0.2 spring-security-oauth-facebook:0.1 休眠:3.6.10.16 执行者:0.3 出口:1.6 csv:0.3.1 数据库迁移:1.2.1 石英:1.0-RC7 资产管道:1.9.6 grails-melody:1.57.0

数据库:PostgreSQL 8.4.20

我尝试了很多解决方案:

我将 Grails 版本更改为 2.4 我将 Hibernate3 更改为 Hibernate4 我将 Postgres 的连接器从 9.0-801.jdbc3 更改为 9.1-901-1.jdbc4 我删除了依赖项,看看它们中的任何一个都不会导致问题 我检查了提取的 WAR 是否在任何文件中都没有差异 我更改了 Java 版本 我更改了 Tomcat 版本 我在另一个系统上测试过

根据我在上面给出的链接的博客上读到的内容,Graeme Rocher 写道,问题可能是由于应用程序中缺少 GORM。但是,在构建 WAR 期间出现了问题 - 依赖项被错误地打包(?)。但是,当 WAR 解包或加载类时,就会出现问题。从博客条目中查看问题的根源,表明问题可能是由于一些荒谬的原因......

有谁知道可能导致此问题的原因,或者我可以调试什么来确定错误的来源? 还有给 grails 开发者的问题:2.2 和 2.3 版本之间发生了什么变化,理论上可能会导致这样的问题?

【问题讨论】:

我们面临着类似的问题,无法应对。我们有 3 个查询停止“工作”并被转换为失败的where 1=1 and 1=1 sql 查询。不是同时!在服务器重新启动后的不同时刻,在发布后。在此之前完美运行的代码,几个月都没有改变,并且在重新启动后再次运行......奇怪,怪异,并且没有解决。三天前我们遇到了一个大问题,一个查询应该只删除实体集合的一小部分,但删除了整个集合。那是备份重新加载日... Grails 2.4.4,Hibernate 4 这里的问题与 grails 2.4.4 中的 where 查询相同。应该取消过期会员的查询,设法取消了我们的整个用户群!这是非常不确定的,取决于应用程序的启动方式。 【参考方案1】:

问题似乎来自grails-datastore-gorm-hibernate-core JAR 中的AbstractHibernateCriterionAdaptercriterionAdaptors HashMap 未正确填充。

这个映射是一个final static HashMap,用于将 GORM 标准映射到 Hibernate 标准。

该问题在应用程序启动时随机出现。 有时填充 HashMap 没有任何问题,有时会出现问题... 此 Hashmap 为 static final,并在应用程序生命周期的剩余时间内保持损坏。这就是为什么您有时会遇到此问题,并且在重新启动后一切正常。

当多个线程同时创建AbstractHibernateCriterionAdapter 对象时,HashMap 可能会损坏。 每个线程调用构造函数和initialize() 方法。 这个方法是synchronized,但synchronized 习惯用法只对访问同一个对象的多个线程有效(https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html)

因此,synchronized 无法正确锁定 initialize() 方法,并且多个线程可以尝试同时填充 criterionAdaptors HashMap。HashMap 不是线程安全的,因为结果 HashMap 被损坏并且缺少一些 Criterions。

如果在此 HashMap 中未找到 GORM Criterion,则该 Criterion 将被静默忽略...这就解释了为什么它会从生成的请求中消失。

我创建了一个 Github 问题:https://github.com/grails/grails-data-mapping/issues/643

【讨论】:

好吧,终于对这个问题进行了合乎逻辑的解释:)。但有一件事让我想知道为什么这个问题只发生在某些人身上?这不可能是 Grails 2.3 / 2.4 的常见问题。又发现了一个规律,虚拟机上不会出现问题... 第一次执行条件请求时会填充 AbstractHibernateCriterionAdapter。所以它可能取决于应用程序的第一标准请求。如果在应用启动时(Bootstrap.groovy?)同时执行了两个请求,则可能会出现该问题,否则不可能出现该问题。它可以解释为什么只有部分应用程序受到影响。 您需要任何进一步的信息来接受此回复吗? 哦,对不起。感谢您的帮助【参考方案2】:

通过 id 以这种方式获取 User 的所有实例是一种奇怪的方式。

你试过了吗?

User.findAllById(userid)

【讨论】:

这只是一个例子。主要问题在于项目中的所有查询都创建了错误的SQL。 如果您正在执行连接,则该方法在 withcriteria 闭包内使用标准连接。

以上是关于“Where query”在生产环境中创建错误的 SQL的主要内容,如果未能解决你的问题,请参考以下文章

在 conda 中创建环境时如何修复错误

在实时环境中创建 PayPal 计费计划

如何根据环境在公用文件夹中创建文件

在 Management Studio 中创建 CHANGE 脚本?

无法在 Pulsar 中创建生产者

UITableView 在动态环境中创建静态单元格