0

正如标题所示,我在尝试将JPA CriteriawithSpring Boot用于特定情况时遇到问题。

通常一切正常,但尝试使用嵌入 ( ) 的String属性搜索存储的数据似乎不起作用。newLine character\n

我能够对Get数据进行编辑,通过前端保存它们,使用多行创建新数据等。但是,'hello\nworld'即使在 MySQL Workbench 中运行此查询有效,当列等于它时尝试搜索它们也不会起作用返回所需的数据:

select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hello\nworld';

澄清一下,我进行搜索的方式是在Get请求中等待一个名为的参数,该参数search具有用户过滤的所有属性。我将它与 a 匹配Regex(其中也有Java 8.0 new Regex \\\\Rfor 匹配multilines(并且它有效))然后我给出我匹配的Service layertheSearch Criteria然后传递给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.

MySQL logs这是触发请求时生成的日志记录(我打开了 Spring Boot 日志记录)的一个示例(在这种情况下,我在我Table ct_thhlastika_press_threats的 in 中存储的数据column description_ena\ns\ndd所以我正在搜索这个,如您所见而不是我之前说的例子hello\nworld


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] - [a\ns\ndd]
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] - [a\ns\ndd]
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 repo中找到它。这个项目是为了我的大学论文。我对添加到 ctThhlastikaPressThreats 控制器和存储库的正则表达式(两者)发表了评论。需要生成db(标准以及用于测试的辅助)(可以通过更改application.properties中的auto-dll来生成)。




更新

我尝试使用System.lineSeparator()(按照@Hermann Steidel下面的答案中的建议)替换文本 newLine \n。但是即使在日志中我们现在可以清楚地看到 equals Predicate 的值具有行分隔符,它仍然不会从数据库返回数据。

我的实施的进一步解释

动态搜索的正确 Get 请求如下所示:

http://localhost:8080/v1/ctThhlastikaPressThreats/search?search=descriptionEn~hello\nworld;@&size=10&page=0&sort=Asc

如您所见,我正在使用一个名为的路径变量search(它具有用户请求的所有属性过滤)以及另外 3 个用于size,pagesort.

对于search变量,我使用 3 个不同的字符来实现最终查询的 OR 和 AND 谓词。这些~是要知道属性在它需要使用相等谓词之前,;它是能够为用户请求的每个属性具有多个值,最后是@触发该属性过滤的结束。

这三个字符Regexed在两个地方。在Controller和中SearchRepository(例如,因为我们专门从这个开始 -> 的CtThhlastasikaPressThreats

最后在 SearchRepository 中,您可以看到我正在触发 2 个查询,一个是从数据库中获取过滤后的数据,另一个是获取数据的计数以用于分页目的,同时最终映射到自定义 DTO。

重现步骤 :

生成数据库后,更改 CtThhlastikaPressThreats 的 2 个正则表达式。为了Controller存在(\w+?)(~|<|>)([(!-/.\\\\R 0-9\p{L});]+)?@和为了SearchRepository存在([(!-/.\\\\R 0-9\p{L})]+)

然后,您可以使用我上面的请求示例,在为特定表和列保存的特定表和列descriptionEn中保存hello\nworld例如值或您输入的任何值(也将其更改为请求)。

我试过但不是解决方案的最后一件事:

将 CtThhlastikaPressThreatsSearchRepository 放入方法中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());

这基本上会改变价值,hellow\nworld所以hello\r\nworld我想它仍然不是理想的解决方案。认为在数据库中它被存储为\nlineSeparators。

现在在日志中您可以看到,当您再次触发 Get Request 时,VARCHAR 值descriptionEn现在确实带有行分隔符,而不是\n(仍然应该被 MySQL 识别)文本。

最后的想法

我相信即使这样

select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hello\nworld';

在 MySQL Workbench 中工作,在尝试包含newLine charor时,介于两者之间的东西可能会破坏请求lineSeparators




如果有任何想法为什么它不能按预期工作,请分享以尝试一下。

感谢您的时间

4

1 回答 1

1

我让它工作。可能不是您想要的答案,但是,如果您将传入的“\n”替换为系统行分隔符,它将得到您想要的。

 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]) - [hello\nworld]

就像我怀疑的那样,在搜索管道的某个地方,它正在转义“\ n”。我不是建议你在控制器上做我建议的事情,我只是想告诉你这是需要发生的事情(某处)它才能工作。

于 2019-02-14T04:19:02.537 回答