正如标题所示,我在尝试将JPA Criteria
withSpring 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 \\\\R
for 匹配multilines
(并且它有效))然后我给出我匹配的Service layer
theSearch 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_en
是a\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
,page
和sort
.
对于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
我想它仍然不是理想的解决方案。认为在数据库中它被存储为\n
lineSeparators。
现在在日志中您可以看到,当您再次触发 Get Request 时,VARCHAR 值descriptionEn
现在确实带有行分隔符,而不是\n
(仍然应该被 MySQL 识别)文本。
最后的想法
我相信即使这样
select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hello\nworld';
在 MySQL Workbench 中工作,在尝试包含newLine char
or时,介于两者之间的东西可能会破坏请求lineSeparators
。
如果有任何想法为什么它不能按预期工作,请分享以尝试一下。
感谢您的时间