如何使用 Spring JpaRepository 转义问号 (?) 字符
How to escape question mark (?) character with Spring JpaRepository
Postgres 定义 additional jsonb Operators 例如 ?|
.
但是,使用 Spring JpaRepository 查询生成器,询问字符始终被视为参数,我不知道如何转义它(单引号字符串内除外,但查询无效).
示例:
@Query(value = "SELECT * FROM public.user u WHERE u.authorities ?| array['ROLE_1', 'ROLE_2']", nativeQuery = true)
错误:
java.lang.IllegalArgumentException: Unable to resolve given parameter name [1] to QueryParameter reference
at org.hibernate.query.internal.QueryParameterBindingsImpl.resolveQueryParameter(QueryParameterBindingsImpl.java:520)
at org.hibernate.query.internal.QueryParameterBindingsImpl.getQueryParameterListBinding(QueryParameterBindingsImpl.java:498)
at org.hibernate.query.internal.AbstractProducedQuery.setParameterList(AbstractProducedQuery.java:560)
有没有办法逃避它,或者有不同的解决方案来使用这些包含 ?
字符的 postgres 本机运算符。
试图用 ??| 逃避它或\?|目前不工作。
注意:我也试过使用自定义方言功能,但它以同样的问题结束。
图书馆:
- 休眠 5.2.16
- 休眠-jpa 2.1
- spring-data-jpa 2.0.6.RELEASE
- postgresql 42.2.2
感谢大家的回复!
作为该特定案例的解决方法,我创建了一个自定义运算符:
CREATE OPERATOR ~~~| (
LEFTARG = jsonb,
RIGHTARG = _text,
PROCEDURE = pg_catalog.jsonb_exists_any
)
然后在我的查询中:WHERE u.authorities ~~~| array['ROLE_1', 'ROLE_2']
@ŁukaszKamiński 在他的回答中详细说明了这个解决方法:
如果无法转义 ?
,您可以创建具有不同名称的重复运算符。
新运营商
Postgres 中 creating operators 的语法:
CREATE OPERATOR name (
PROCEDURE = function_name
[, LEFTARG = left_type ] [, RIGHTARG = right_type ]
[, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
[, RESTRICT = res_proc ] [, JOIN = join_proc ]
[, HASHES ] [, MERGES ]
)
如果 ?|
在 jsonb
中使用,它将是:
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
我以^|
为例,替代名称。它可以是此列表中的任何序列:+ - * / < > = ~ ! @ # % ^ & |
?`.
您可以通过查询 pg_catalog.pg_operator table.
找到您感兴趣的运算符的当前定义
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
您还可以使用 pgAdmin 等 GUI 工具并浏览 pg_catalog
以获得 SQL 定义以供重用。
启用索引
如果要为此 "new" 运算符使用索引,您将需要创建新的运算符 class 和可选的系列。在我们的例子中,我们需要两者,因为我们不能将它添加到现有系列中,因为默认运算符已经采用 strategy slot.
就像运算符一样,建议使用 pgAdmin 等 GUI 工具浏览运算符 classes 并复制粘贴即可。
首先,我们获取我们复制的运算符的 OID:
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
运算符家族也是如此(我们将从 operator class table 获取它),我们正在寻找 gin class 因为这是支持 ?|
的那个。使用opcdefault
,因为有可选的class jsonb_path_ops
不支持这个运算符:
SELECT opcfamily
FROM pg_opclass
WHERE opcintype = (SELECT oid FROM pg_type WHERE typname = 'jsonb')
AND opcmethod = (SELECT oid FROM pg_am WHERE amname = 'gin')
AND opcdefault
然后我们得到 strategy used by operator 我们复制了:
SELECT amopstrategy,
(SELECT typname FROM pg_type WHERE oid = amoplefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amoprighttype) AS right_t,*
FROM pg_amop
WHERE amopfamily = 4036 --family oid
AND amopopr = 3248 --operator oid
SELECT amprocnum, amproc::text, pg_get_function_identity_arguments(amproc::oid) AS args,
(SELECT typname FROM pg_type WHERE oid = amproclefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amprocrighttype) AS right_t,*
FROM pg_amproc
WHERE amprocfamily = 4036 --op family
这让我们想到了 operator class。如果运算符家族不存在,它将创建它。
CREATE OPERATOR CLASS jsonb_ops_custom
FOR TYPE jsonb USING gin AS
OPERATOR 10 ^|(jsonb, _text),
FUNCTION 1 gin_compare_jsonb(text, text),
FUNCTION 2 gin_extract_jsonb(jsonb, internal, internal),
FUNCTION 3 gin_extract_jsonb_query(jsonb, internal, smallint, internal, internal, internal, internal),
FUNCTION 4 gin_consistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal, internal),
FUNCTION 6 gin_triconsistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal);
现在您只需要使用创建的运算符名称创建索引,例如:
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
你应该可以使用索引:
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];
您可以直接调用函数 jsonb_exists_any()
。
所以在你的情况下它将是
jsonb_exists_any(u.authorities::jsonb, array['ROLE_1', 'ROLE_2'])
Postgres 定义 additional jsonb Operators 例如 ?|
.
但是,使用 Spring JpaRepository 查询生成器,询问字符始终被视为参数,我不知道如何转义它(单引号字符串内除外,但查询无效).
示例:
@Query(value = "SELECT * FROM public.user u WHERE u.authorities ?| array['ROLE_1', 'ROLE_2']", nativeQuery = true)
错误:
java.lang.IllegalArgumentException: Unable to resolve given parameter name [1] to QueryParameter reference
at org.hibernate.query.internal.QueryParameterBindingsImpl.resolveQueryParameter(QueryParameterBindingsImpl.java:520)
at org.hibernate.query.internal.QueryParameterBindingsImpl.getQueryParameterListBinding(QueryParameterBindingsImpl.java:498)
at org.hibernate.query.internal.AbstractProducedQuery.setParameterList(AbstractProducedQuery.java:560)
有没有办法逃避它,或者有不同的解决方案来使用这些包含 ?
字符的 postgres 本机运算符。
试图用 ??| 逃避它或\?|目前不工作。
注意:我也试过使用自定义方言功能,但它以同样的问题结束。
图书馆:
- 休眠 5.2.16
- 休眠-jpa 2.1
- spring-data-jpa 2.0.6.RELEASE
- postgresql 42.2.2
感谢大家的回复!
作为该特定案例的解决方法,我创建了一个自定义运算符:
CREATE OPERATOR ~~~| (
LEFTARG = jsonb,
RIGHTARG = _text,
PROCEDURE = pg_catalog.jsonb_exists_any
)
然后在我的查询中:WHERE u.authorities ~~~| array['ROLE_1', 'ROLE_2']
@ŁukaszKamiński 在他的回答中详细说明了这个解决方法:
如果无法转义 ?
,您可以创建具有不同名称的重复运算符。
新运营商
Postgres 中 creating operators 的语法:
CREATE OPERATOR name (
PROCEDURE = function_name
[, LEFTARG = left_type ] [, RIGHTARG = right_type ]
[, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
[, RESTRICT = res_proc ] [, JOIN = join_proc ]
[, HASHES ] [, MERGES ]
)
如果 ?|
在 jsonb
中使用,它将是:
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
我以^|
为例,替代名称。它可以是此列表中的任何序列:+ - * / < > = ~ ! @ # % ^ & |
?`.
您可以通过查询 pg_catalog.pg_operator table.
找到您感兴趣的运算符的当前定义SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
您还可以使用 pgAdmin 等 GUI 工具并浏览 pg_catalog
以获得 SQL 定义以供重用。
启用索引
如果要为此 "new" 运算符使用索引,您将需要创建新的运算符 class 和可选的系列。在我们的例子中,我们需要两者,因为我们不能将它添加到现有系列中,因为默认运算符已经采用 strategy slot.
就像运算符一样,建议使用 pgAdmin 等 GUI 工具浏览运算符 classes 并复制粘贴即可。
首先,我们获取我们复制的运算符的 OID:
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
运算符家族也是如此(我们将从 operator class table 获取它),我们正在寻找 gin class 因为这是支持 ?|
的那个。使用opcdefault
,因为有可选的class jsonb_path_ops
不支持这个运算符:
SELECT opcfamily
FROM pg_opclass
WHERE opcintype = (SELECT oid FROM pg_type WHERE typname = 'jsonb')
AND opcmethod = (SELECT oid FROM pg_am WHERE amname = 'gin')
AND opcdefault
然后我们得到 strategy used by operator 我们复制了:
SELECT amopstrategy,
(SELECT typname FROM pg_type WHERE oid = amoplefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amoprighttype) AS right_t,*
FROM pg_amop
WHERE amopfamily = 4036 --family oid
AND amopopr = 3248 --operator oid
SELECT amprocnum, amproc::text, pg_get_function_identity_arguments(amproc::oid) AS args,
(SELECT typname FROM pg_type WHERE oid = amproclefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amprocrighttype) AS right_t,*
FROM pg_amproc
WHERE amprocfamily = 4036 --op family
这让我们想到了 operator class。如果运算符家族不存在,它将创建它。
CREATE OPERATOR CLASS jsonb_ops_custom
FOR TYPE jsonb USING gin AS
OPERATOR 10 ^|(jsonb, _text),
FUNCTION 1 gin_compare_jsonb(text, text),
FUNCTION 2 gin_extract_jsonb(jsonb, internal, internal),
FUNCTION 3 gin_extract_jsonb_query(jsonb, internal, smallint, internal, internal, internal, internal),
FUNCTION 4 gin_consistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal, internal),
FUNCTION 6 gin_triconsistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal);
现在您只需要使用创建的运算符名称创建索引,例如:
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
你应该可以使用索引:
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];
您可以直接调用函数 jsonb_exists_any()
。
所以在你的情况下它将是
jsonb_exists_any(u.authorities::jsonb, array['ROLE_1', 'ROLE_2'])