是否可以在 Spring Data JPA Repository 的 @Query 注释中使用 PostgreSQL 匿名块(PL/pgSQL)?
Posted
技术标签:
【中文标题】是否可以在 Spring Data JPA Repository 的 @Query 注释中使用 PostgreSQL 匿名块(PL/pgSQL)?【英文标题】:Is it possible to use PostgreSQL anonymous block (PL/pgSQL) within the @Query annotation of Spring Data JPA Repository? 【发布时间】:2022-01-19 08:58:47 【问题描述】:我需要调用一个带参数的匿名块。
@Repository
public interface FinAccountRepository extends JpaRepository<FinAccount, Long>
@Modifying
@Query(nativeQuery = true, value =
"DO $$ <<credit_account>>\n" +
"DECLARE\n" +
" nNewBalance numeric(19,2);\n" +
" nNewId bigint;\n" +
"BEGIN\n" +
" update fin_account set balance = balance + :amount where id = :account\n" +
" returning balance into nNewBalance;\n" +
" select nextval('seq_fin_account_def_id') into nNewId;\n" +
" insert into fin_account_definition(id, account, transaction, balance)\n" +
" values (nNewId, :account, :tx, nNewBalance); \n" +
"END credit_account $$;")
void credit(@Param("tx") UUID tx, @Param("account") Long account, @Param("amount") BigDecimal amount);
以下代码抛出错误
org.springframework.dao.DataIntegrityViolationException: could not execute native bulk manipulation query; SQL [DO $$
DECLARE
nNewBalance numeric(19,2);
BEGIN
update fin_account set balance = balance - :amount where id = :account
returning fa.balance into nNewBalance;
insert into fin_account_definition(id, account, transaction, balance)
values (nextval('seq_fin_account_def_id'), :account, :tx, nNewBalance);
END $$;]; nested exception is org.hibernate.exception.DataException: could not execute native bulk manipulation query
. . .
Caused by: org.hibernate.exception.DataException: could not execute native bulk manipulation query
. . .
Caused by: org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
at org.postgresql.core.v3.SimpleParameterList.bind(SimpleParameterList.java:69) ~[postgresql-42.2.24.jar:42.2.24]
at org.postgresql.core.v3.SimpleParameterList.setLiteralParameter(SimpleParameterList.java:128) ~[postgresql-42.2.24.jar:42.2.24]
at org.postgresql.jdbc.PgPreparedStatement.bindLiteral(PgPreparedStatement.java:1042) ~[postgresql-42.2.24.jar:42.2.24]
at org.postgresql.jdbc.PgPreparedStatement.setNumber(PgPreparedStatement.java:520) ~[postgresql-42.2.24.jar:42.2.24]
at org.postgresql.jdbc.PgPreparedStatement.setBigDecimal(PgPreparedStatement.java:337) ~[postgresql-42.2.24.jar:42.2.24]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setBigDecimal(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.type.descriptor.sql.DecimalTypeDescriptor$1.doBind(DecimalTypeDescriptor.java:47) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:73) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.custom.sql.NamedParamBinder.bind(NamedParamBinder.java:34) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.query.spi.NativeSQLQueryPlan.performExecuteUpdate(NativeSQLQueryPlan.java:102) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
... 160 common frames omitted
我也尝试使用序数参数 - 结果是一样的。 但是,没有绑定参数的匿名块被正确调用。 我对从 Spring Data JPA Repository 的方法将参数传递给 postgresql 匿名块的能力感兴趣。
【问题讨论】:
【参考方案1】:您不需要为此使用 PL/pgSQL。这可以在单个 SQL 语句中完成:
with changed_account as (
update fin_account
set balance = balance + :amount
where id = :account
returning balance, id
)
insert into fin_account_definition(id, account, transaction, balance)
select nextval('seq_fin_account_def_id'), c.id, :tx, c.balance
from changed_account c;
【讨论】:
以上是关于是否可以在 Spring Data JPA Repository 的 @Query 注释中使用 PostgreSQL 匿名块(PL/pgSQL)?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 Spring Data JPA Repository 的 @Query 注释中使用 PostgreSQL 匿名块(PL/pgSQL)?
如何在 Spring Data (JPA) 派生查询中按多个属性排序?
是否有适用于 JPA、spring-data、spring-data-rest 的通用 REST 查询语言
即使 JPA 实体不脏,我是不是可以强制 spring-data 更新可审计字段?