正如标题所示,我在尝试将JPA Criteria
与特定情况下的Spring Boot
一起使用时遇到问题。
一般来说,一切正常,但试图使用嵌入newLine character
String
属性搜索存储的数据(n
)似乎不起作用。
我能够Get
数据,编辑它们,通过我的前端保存它们,创建具有多行的新数据等,但是尝试在例如列等于'hellonworld'
时搜索它们,即使运行此查询在MySQL Workbench中返回所需的数据,它也不起作用:
select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hellonworld';
澄清一下,我进行搜索的方式是在Get
请求一个名为search
的参数中等待,该参数具有用户过滤的所有属性。我正在将其与Regex
匹配(该Java 8.0 new Regex \\R
内部也有用于与multilines
匹配的Search Criteria
(并且它有效)),然后我给Service layer
我匹配的,然后传递给Jpa Criteria Repository
来解析它们并generating the Predicates
(再次与Regex and \\R
匹配以创建用于过滤的最终Predicate with OR and ANDs
),然后triggering the query
, 然后another query called count
实现Pagination
,最后mapping
到自定义对象并将其返回。
我调试了每个步骤,最终的谓词确实生成了我想要的查询,但数据库没有返回预期的数据。所以我真的很困惑,因为正如我所说,查询确实适用于MySQL Workbench
.
这是触发请求时生成的日志记录(我打开了 Spring Boot 日志记录MySQL logs
)的示例(在这种情况下,我在column description_en
Table ct_thhlastika_press_threats
中存储的数据是ansndd
所以我正在寻找这个,如您所见,而不是我之前hellonworld
说过的示例:
2019-02-12 16:01:01.929 DEBUG 18368 --- [nio-8080-exec-2] org.hibernate.SQL : select ctthhlasti0_.id as col_0_0_, ctthhlasti0_.act_code as col_1_0_, ctthhlasti0_.description_en as col_2_0_, ctthhlasti0_.remarks as col_3_0_ from ct_thhlastika_press_threats ctthhlasti0_ where 1=1 and ctthhlasti0_.description_en=? order by ctthhlasti0_.id asc limit ?
2019-02-12 16:01:01.933 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [ansndd]
2019-02-12 16:01:01.944 DEBUG 18368 --- [nio-8080-exec-2] org.hibernate.SQL : select count(ctthhlasti0_.id) as col_0_0_ from ct_thhlastika_press_threats ctthhlasti0_ where 1=1 and ctthhlasti0_.description_en=?
2019-02-12 16:01:01.944 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [ansndd]
2019-02-12 16:01:01.946 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor : extracted value ([col_0_0_] : [BIGINT]) - [0]
对于任何有兴趣进一步研究代码的人,你可以找到它 Github 存储库。该项目是为了我的大学论文。我为添加到ctThhlastikaPressThreat Controller and Repository的正则表达式(两者)中发表了评论。需要生成数据库(标准数据库和测试辅助数据库)(可以通过更改 application.properties 中的自动 dll 来生成)。
更新
我尝试使用System.lineSeparator()
(如@Hermann Steidel
在答案波纹管中的建议)替换文本换行符n
。但是,即使在日志中,我们现在可以清楚地看到等于谓词的值具有行分隔,但它仍然不会从数据库返回数据。
对我的实现的进一步解释
动态搜索的正确 Get 请求如下所示:
http://localhost:8080/v1/ctThhlastikaPressThreats/search?search=descriptionEn~hellonworld;@&size=10&page=0&sort=Asc
如您所见,我正在使用一个名为search
的路径变量(它具有用户请求的所有属性过滤)以及另外 3 个用于size
、page
和sort
的变量。
对于search
变量,我使用 3 个不同的字符来实现最终查询的 OR 和 AND 谓词。这些是~
,即知道属性之前需要使用相等的谓词,;
能够为用户请求的每个属性具有多个值,最后是触发此属性过滤结束的@
。
这 3 个角色正在两个地方Regexed
。在Controller
和SearchRepository
中(例如,因为我们专门从这个开始 ->CtThhlastasikaPressThreats
)
最后,在 SearchRepository 中,您可以看到我触发了 2 个查询,一个是从数据库中获取过滤后的数据,另一个是获取用于分页目的的数据计数,同时最终映射到自定义 DTO。
重现步骤:
生成数据库后,更改 CtThhlastikaPressThreat 的 2 个正则表达式。为了(w+?)(~|<|>)([(!-/.\\R 0-9p{L});]+)?@
Controller
,为了([(!-/.\\R 0-9p{L})]+)
SearchRepository
。
然后,您可以使用我上面请求的示例,例如,在数据库中保存了特定表和列descriptionEn
的值为hellonworld
或您输入的任何值(也将其更改为请求)。
最后一件事我尝试了,但不是解决方案:
放入 CtThhlastikaPressThreatSearchRepository 中的方法search
(在第 61 行之后):
predicate = builder.equal(root.get(param.getKey()), match.toString());
将其设为 :
match = match.toString().replace("\n", System.lineSeparator());
predicate = builder.equal(root.get(param.getKey()), match.toString());
这基本上会将值从hellownworld
更改为hellornworld
,所以我想它仍然不是所需的解决方案。认为在数据库中它被存储为行分隔符的n
。
现在在日志中,您可以看到,当您再次触发获取请求时,descriptionEn
的 VARCHAR 值现在确实带有行分隔而不是n
(MySQL 仍应识别)文本。
结语
我相信即使这样
select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hellonworld';
在MySQL工作台中工作,当尝试同时包含newLine char
或lineSeparators
时,介于两者之间的某些内容可能会破坏请求。
如果有任何想法为什么它不能按预期工作,请分享以尝试一下。
谢谢你的时间
我让它工作了。可能不是您想要的答案,但是,如果您将传入的""替换为系统行分隔符,它将得到您想要的答案。
search = search.replace("\n", System.getProperty("line.separator"));
try {
return ctThhlastikaPressThreatsService.searchCtThhlastikaPressThreats(producedSearchCriterias(search), size, page, sort);
如果你看一下参数值日志记录,你会看到参数现在是
extracted value ([col_2_0_] : [VARCHAR]) - [hello
world]
而不是
extracted value ([col_2_0_] : [VARCHAR]) - [hellonworld]
就像我怀疑的那样,在搜索管道中的某个地方,它正在转义""。我并不是建议你在控制器上做我建议的事情,我只是想告诉你这是它需要发生的事情(在某个地方)才能工作。