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提供很多特殊的数据类型(数组、坐标等)有时写法比较特殊、我们都可以采用这样的方式进行查询。

相关推荐
ly768919 小时前
PostgreSQL 备份恢复策略:pg_basebackup、WAL 归档与 PITR 在企业 Java 系统中的落地
java·数据库·postgresql·pitr·pg_basebackup·wal 归档
ly768920 小时前
Spring Boot 集成 PostgreSQL 的连接池调优:HikariCP、prepared statement 与服务器资源边界
spring boot·postgresql·hikaricp·连接池调优
一直在努力学习的菜鸟1 天前
PostgreSQL流复制和PostgreSQL高可用的区别
postgresql
ss2731 天前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql
一直在努力学习的菜鸟2 天前
PostgreSQL流复制实现主从数据同步
postgresql
IvorySQL2 天前
PostgreSQL 日报| PG19 主备切换挂起修复(10 月 17 日)
数据库·postgresql
ly76892 天前
PostgreSQL 流复制与高可用切换:主从延迟、同步提交与 Spring Boot 读写分离的边界
数据库·spring boot·postgresql·读写分离·流复制·高可用切换
骑着蜗牛撵大象3272 天前
ToolJet + PostgreSQL:后台表格、查询和流程,一次搭成可远程访问的业务系统
数据库·低代码·docker·postgresql·内部工具·tooljet
wno7042 天前
postgresSQL压缩版安装与基本命令
数据库·postgresql
瀚高PG实验室2 天前
瀚高数据库常用系统表查询入门指南(附常用SQL)
数据库·sql·postgresql·瀚高数据库