我的目标是在运行时在 PostreSQL 数据库中创建不同的物化视图,我想使用 Spring JPA EntityManager 和 Hibernate。我在 stackoverflow 上研究了类似的问题,但没有一个能解决我的问题,我真的希望在这里得到建议。我使用 Spring Boot 3.3.3、Hibernate 6 和 PostrgreSQL。
我的问题是:如何使用不同类型的参数(视图名称、条件)配置本机sql查询,以在postgres数据库中成功创建新的物化视图?
我有一张桌子,问题是这样的:
create table if not exists question(
id uuid primary key not null,
type uuid not null, -- maps to Type table
content text unique not null,
grade int not null,
created_at timestamp with time zone
);
我尝试使用类似下面示例的某种类型
Query query = entityManager.createNativeQuery(
"create materialized view if not exists :name as" +
" select * from question q" +
" where" +
" q.type in (:typesList)" +
" and" +
" q.grade <= :maxGrade" +
" and" +
" q.grade >= :minGrade"
)
.setParameter("name", name) // String name
.setParameter("typesList", list) // List<UUID> list
.setParameter("maxGrade", maxGrade) // Integer maxGrade
.setParameter("minGrade", minGrade); // Integer minGrade
query.executeUpdate();
但它执行时出现异常(此异常告诉我查询中第一个参数(
:name
)的位置):JDBC exception executing SQL [create materialized view if not exists ? as select * from question q where q.type in (?,?) and q.grade <= ? and q.grade >= ?] [ERROR: syntax error at or near "$1"
在下一步中,我停止使用视图名称参数,我的查询如下所示:
Query query = entityManager.createNativeQuery(
"create materialized view if not exists " + name + " as" +
" select * from question q" +
" where" +
" q.type in (:typesList)" +
" and" +
" q.grade <= :maxGrade" +
" and" +
" q.grade >= :minGrade"
)
.setParameter("typesList", list) // List<UUID> list
.setParameter("maxGrade", maxGrade) // Integer maxGrade
.setParameter("minGrade", minGrade); // Integer minGrade
query.executeUpdate();
这也失败了,但有例外:
Caused by: org.postgresql.util.PSQLException: ERROR: materialized views may not be defined using bound parameters
最后唯一正确工作的情况是:
Query query = entityManager.createNativeQuery(
"create materialized view if not exists " + name +" as" +
" select * from question" +
" where" +
" type in (" + buildTypeCondition(list) + ")" +
" and" +
" grade <= " + (maxGrade) +
" and" +
" grade >= " + (minGrade)
);
//buildTypeCondition here creates a string like "'<uuid1>', '<uuid2>', ..."
但它的代码确实很糟糕,为了避免 SQL 注入,我需要摆脱将字符串参数直接注入 sql 查询的情况。
您能帮我一下吗,在这种情况下我应该如何正确使用参数?我应该如何从
IN (uuid, uuid, ...)
参数创建有效的 List<UUID>
SQL 条件?
DDL 语句不支持参数。您必须手动生成 SQL 并清理参数。
您不需要
EntityManager
,没有实体需要管理。使用DataSource
。
在运行时生成物化视图听起来很粗略。并且不能轻松地与 Hibernate 一起工作。考虑不同的解决方案。