在我的MySQL数据库(8.0.23)上,我有一个JSON列,即多值索引。我想使用QueryDSL来使用JSON_CONTAINS
索引进行查询。我已经验证了该列的索引是否正确,并且在运行查询时正在使用该索引;例如,
EXPLAIN SELECT *
FROM user u
WHERE JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John'));
指示正在按预期使用多值索引。
到目前为止,我已经尝试过
Expressions.booleanTemplate("JSON_CONTAINS(JSON_EXTRACT({0}, '$'), JSON_QUOTE({1})) = 1", expression, str)
并让BooleanExpression
作为谓词使用QueryDSL实现相同的目标;请注意,如果没有= 1
,执行它将引发以下错误。
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
似乎阻止索引用于相同的查询。例如,
EXPLAIN SELECT *
FROM user u
WHERE JSON_CONTAINS(JSON_EXTRACT(u.alias,'$'), JSON_QUOTE('John')) = 1;
表示没有使用索引。!= 0
,IS TRUE
或IS 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
,以便使用多值索引?
发布于 2022-06-10 20:19:37
我为这件事找到了一种很好的解决办法。通过扩展Hibernate方言,您可以创建返回任意SQL的自定义HQL函数。
因此,您可以定义具有自定义HQL函数custom_json_contains
的方言,如:
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)中使用此方法:
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:
JSON_CONTAINS(JSON_EXTRACT(u.alias, '$'), JSON_QUOTE('John')) AND 1=1
= 1
仍然存在,但至少现在它什么也不做了!
https://stackoverflow.com/questions/71489375
复制相似问题