springboot+querydsl+jpa+pgsql自定义函数完成jsonb类型指定字段like(模糊匹配)

​ 记录在querydsl+jpa+pgsql的项目中、有事会用到pgsql的特有的数据类型比如jsonb类型、然有一些特殊的查询querydsl是不支持的、这就需要我们自定义函数来实现。

例如:在pgsql使用jsonb数据接口实现模糊查询其中的一个字段值。

表&实体信息如下:

sql 复制代码
create table if not exists rule_trigger_record
(
    id               bigint not null
        constraint rule_trigger_record_pk primary key,
    segment_field    varchar(32)[],
    involved_company jsonb,
    event_title      varchar(256)
);

comment on column rule_trigger_record.id is '记录表ID';

comment on column rule_trigger_record.segment_field is '细分领域';

comment on column rule_trigger_record.involved_company is '涉及企业信息';

comment on column rule_trigger_record.event_title is '标题';
java 复制代码
@TypeDefs({
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
        @TypeDef(name = "list-array", typeClass = ListArrayType.class)
})
@Data
@Entity
@Table(name = "rule_trigger_record")
public class RuleTriggerRecord {
    
    @Id
    @Column
    private Long id;
    
    /**
     * 事件标题 @Transient
     */
    private String eventTitle;

    /**
     * 涉及公司
     */
    @Type(type = "jsonb")
    @Column(name = "involved_company", columnDefinition = "jsonb")
    private List<InvolvedCompany> involvedCompany;
    
    /**
     * 细分领域
     */
    @Type(type = "list-array")
    @Column(name = "segment_field")
    private List<String> segmentField;


    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class InvolvedCompany {

        private Long companyId;

        private String companyName;

    }


}

可能需要这个依赖、来支持复杂类型:

xml 复制代码
<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.12.0</version>
</dependency>

就是说很快咱就能写出来、SQL语句的一个写法完成需求:

sql 复制代码
SELECT *
FROM rule_trigger_record
WHERE EXISTS(SELECT 1 FROM jsonb_array_elements(involved_company) AS ic WHERE ic ->> 'companyName' LIKE '爱奇艺%');

但是在querydsl+jpa的写法就要想麻烦一点了、因要尽可能的不出现自定义SQL,不便于维护。

所以使用jpa的自定义函数步骤如下:

  • 自定义函数

  • Custom PostgreSQL Dialect 自定义SQL方言

  • 自定义函数使用

一、自定义函数

新建类JsonbFieldLikeFunction继承SQLFunction

java 复制代码
/**
 * jsonb 指定字段 like 
 *
 * @author 傲寒
 * @date 2023/06/09
 */
public class JsonbFieldLikeFunction implements SQLFunction {

    @Override
    public boolean hasArguments() {
        return true;
    }

    @Override
    public boolean hasParenthesesIfNoArguments() {
        return true;
    }

    @Override
    public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
        return BooleanType.INSTANCE;
    }

    @Override
    public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException {
        if (arguments.size() != 3) {
            throw new IllegalArgumentException("jsonb_field_like requires 3 arguments!");
        }
        //最终语句 EXISTS(SELECT 1 FROM jsonb_array_elements({0}) AS ic WHERE ic ->> {1} LIKE '%{2}%')
        return "EXISTS(SELECT 1 FROM jsonb_array_elements(" + arguments.get(0).toString() + ") AS ic " +
                "WHERE ic ->> " + arguments.get(1).toString() + " LIKE concat('%'," + arguments.get(2).toString() + ",'%'))";
    }
}
二、自定义数据方言并配置

继承PostgreSQL95Dialect提供的方言配置

java 复制代码
public class CustomPostgreSQLDialect extends PostgreSQL95Dialect {

    public CustomPostgreSQLDialect() {
        super();
        this.registerFunction("jsonb_field_like", new JsonbFieldLikeFunction());
    }

}

然后再springboot配置文件中指定方言:

yaml 复制代码
spring:
  jpa:
    properties:
      hibernate:
      	# 方言配置全限定类名
        dialect: xxx.xxx.xxx.dialect.CustomPostgreSQLDialect
三、自定义函数使用

配置JPAQueryFactory的bean

java 复制代码
@Configuration
@Slf4j
public class JpaConfig  {

    @Bean
    public JPAQueryFactory qFactory(EntityManager entityManager) {
        return new JPAQueryFactory(entityManager);
    }

}

querydsl测试编写:

java 复制代码
 public void test() {
        //Q类
        QRuleTriggerRecord qRuleTriggerRecord = QRuleTriggerRecord.ruleTriggerRecord;
        String companyName = "爱奇艺";
        final BooleanTemplate template = Expressions.booleanTemplate(
                "jsonb_field_like({0},{1},{2})",
                qRuleTriggerRecord.involvedCompany,
                "companyName",
                companyName
        );
        BooleanBuilder whereEx = new BooleanBuilder();
        whereEx.and(template.isTrue());
        final List<RuleTriggerRecord> fetch = qFactory.selectFrom(qRuleTriggerRecord)
                .where(whereEx)
                .fetch();
        System.out.println(fetch);
    }

​ 这样就完成了自定义函数使用、反正pgsql提供很多特殊的数据类型(数组、坐标等)有时写法比较特殊、我们都可以采用这样的方式进行查询。

相关推荐
睡不醒男孩03082328 分钟前
第七篇:揭秘 PostgreSQL 数据库内核级管控:CLup 深度架构设计与高可用底座技术白皮书
数据库·postgresql·clup
医疗信息化王工5 小时前
医院自律端系统——预警处置模块全栈实战(ASP.NET Core + Vue3 + Quartz 定时调度)
mysql·postgresql·vue·asp.net core·quartz
IvorySQL5 小时前
PostgreSQL 技术日报 (6月9日)|PL/SQL 迁移自动化,前沿峰会即将启幕
sql·postgresql·自动化
睡不醒男孩0308235 小时前
第八篇:如何构建一站式 PostgreSQL 性能优化与智能管控平台?从盲目排查到 CLup 自动化运维演进
运维·postgresql·性能优化
睡不醒男孩0308235 小时前
第五篇:2026年企业级 PostgreSQL 高可用方案深度横评:Patroni vs. CLup 架构与可靠性全面对决
数据库·postgresql·架构
哭哭啼7 小时前
pgSql 事务篇
java·数据库·postgresql
snow@li8 小时前
数据库:MySQL vs PostgreSQL 详尽对比(2026版)
java·mysql·postgresql
J.Kuchiki8 小时前
【PostgreSQL 内核学习:平衡 K 路归并(Balanced k-way Merge)】
数据库·学习·postgresql
lvbinemail8 小时前
【无标题】
数据库·postgresql·zabbix·监控
岳麓丹枫00110 小时前
PG数据库无法接受连接问题分析定位
数据库·postgresql