"Where query" 在生产中创建错误 SQL
"Where query" creates wrong SQL on production
我必须将 Spring 从 1.2.7 更新到 2.0,并将 Grails 从 2.2.0 更新到 2.3.11。在解决了几个典型的更新问题后,我开始搭建一个WAR到测试服务器。一切似乎都很好。但是部署了几次之后就遇到了问题
有时(没有规则)服务器有 100% CPU 使用率 -> OutOfMemeryError 或应用程序抛出错误 500。调试后,我发现这些问题的原因不正确 SQL查询。
哪里查询:
UserRole.find{role.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}
检索整个 table。 动态查找器或标准不会导致此问题。
我发现有两个人有类似的问题:
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-安全核心: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-旋律: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版本
- 我在另一个系统上测试过
根据我在 link 我上面给出的博客上读到的内容,Graeme Rocher 写道,问题可能是由于应用程序中缺少 GORM。然而,问题是在 WAR 的构建过程中出现的——依赖项被错误地打包(?)。但是当 WAR 解包或 类 加载时,问题就出现了。从blog entry看问题的根源,表明问题可能是由于一些荒谬的原因...
有谁知道是什么导致了这个问题,或者我可以调试什么来确定错误的来源?
以及 grails dev 的问题:2.2 版和 2.3 版之间发生了什么理论上可能导致此类问题的变化?
问题似乎来自 grails-datastore-gorm-hibernate-core
JAR 中的 AbstractHibernateCriterionAdapter
。
criterionAdaptors
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 已损坏并且缺少一些条件。
如果在此 HashMap 中未找到 GORM 标准,则会默默地忽略该标准...这解释了为什么它会从生成的请求中消失。
我创建了一个 Github 问题:https://github.com/grails/grails-data-mapping/issues/643
通过 id 以这种方式获取所有 User 实例的方式很奇怪。
你试过吗?
User.findAllById(userid)
我必须将 Spring 从 1.2.7 更新到 2.0,并将 Grails 从 2.2.0 更新到 2.3.11。在解决了几个典型的更新问题后,我开始搭建一个WAR到测试服务器。一切似乎都很好。但是部署了几次之后就遇到了问题
有时(没有规则)服务器有 100% CPU 使用率 -> OutOfMemeryError 或应用程序抛出错误 500。调试后,我发现这些问题的原因不正确 SQL查询。
哪里查询:
UserRole.find{role.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}
检索整个 table。 动态查找器或标准不会导致此问题。
我发现有两个人有类似的问题:
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-安全核心: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-旋律: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版本
- 我在另一个系统上测试过
根据我在 link 我上面给出的博客上读到的内容,Graeme Rocher 写道,问题可能是由于应用程序中缺少 GORM。然而,问题是在 WAR 的构建过程中出现的——依赖项被错误地打包(?)。但是当 WAR 解包或 类 加载时,问题就出现了。从blog entry看问题的根源,表明问题可能是由于一些荒谬的原因...
有谁知道是什么导致了这个问题,或者我可以调试什么来确定错误的来源? 以及 grails dev 的问题:2.2 版和 2.3 版之间发生了什么理论上可能导致此类问题的变化?
问题似乎来自 grails-datastore-gorm-hibernate-core
JAR 中的 AbstractHibernateCriterionAdapter
。
criterionAdaptors
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 已损坏并且缺少一些条件。
如果在此 HashMap 中未找到 GORM 标准,则会默默地忽略该标准...这解释了为什么它会从生成的请求中消失。
我创建了一个 Github 问题:https://github.com/grails/grails-data-mapping/issues/643
通过 id 以这种方式获取所有 User 实例的方式很奇怪。
你试过吗?
User.findAllById(userid)