首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否有QueryDSL表示JSON_CONTAINS谓词?

是否有QueryDSL表示JSON_CONTAINS谓词?
EN

Stack Overflow用户
提问于 2022-03-15 21:43:53
回答 1查看 381关注 0票数 3

在我的MySQL数据库(8.0.23)上,我有一个JSON列,即多值索引。我想使用QueryDSL来使用JSON_CONTAINS索引进行查询。我已经验证了该列的索引是否正确,并且在运行查询时正在使用该索引;例如,

代码语言:javascript
运行
复制
EXPLAIN SELECT *
FROM user u
WHERE JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John'));

指示正在按预期使用多值索引。

到目前为止,我已经尝试过

代码语言:javascript
运行
复制
Expressions.booleanTemplate("JSON_CONTAINS(JSON_EXTRACT({0}, '$'), JSON_QUOTE({1})) = 1", expression, str)

并让BooleanExpression作为谓词使用QueryDSL实现相同的目标;请注意,如果没有= 1,执行它将引发以下错误。

代码语言:javascript
运行
复制
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362)
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74)
    at org.hibernate.hql.internal.ast.ErrorTracker.throwQueryException(ErrorTracker.java:93)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:282)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
    at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:636)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:748)

实际上,= 1似乎阻止索引用于相同的查询。例如,

代码语言:javascript
运行
复制
EXPLAIN SELECT *
FROM user u
WHERE JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John')) = 1;

表示没有使用索引。!= 0IS TRUEIS NOT FALSE也是如此

因此,我遇到的问题是,在使用QueryDSL时,我还没有找到一种在没有= 1的情况下在JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John'))上使用= 1的方法。但是,当MySQL的末尾有= 1时,它似乎没有使用多值索引

我尝试过来自https://stackoverflow.com/a/68684997/18476687的建议,但到目前为止没有什么好运气。

是否有一种方法来表示JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John')),而不使用QueryDSL上的= 1,以便使用多值索引?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-10 20:19:37

我为这件事找到了一种很好的解决办法。通过扩展Hibernate方言,您可以创建返回任意SQL的自定义HQL函数。

因此,您可以定义具有自定义HQL函数custom_json_contains的方言,如:

代码语言:javascript
运行
复制
public class CustomMySQL8Dialect extends MySQL8Dialect {
    public CustomMySQL8Dialect() {
        registerFunction("custom_json_contains", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN, "JSON_CONTAINS(JSON_EXTRACT(?1, ?2), JSON_QUOTE(?3)) AND 1"));
    }
}

然后可以在QueryDSL where子句(或HQL)中使用此方法:

代码语言:javascript
运行
复制
public static <T> BooleanExpression jsonContains(Expression<T> expression, String path, String str) {
    return Expressions.booleanTemplate("CUSTOM_JSON_CONTAINS({0}, {1}, {2}) = 1", expression, path, str);
}

这将使Hibernate呈现以下SQL:

代码语言:javascript
运行
复制
JSON_CONTAINS(JSON_EXTRACT(u.alias, '$'), JSON_QUOTE('John')) AND 1=1

= 1仍然存在,但至少现在它什么也不做了!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71489375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档