栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义JPA函数,在specification中实现位运算

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义JPA函数,在specification中实现位运算

背景

1. 项目中使用一个 32 位的int 类型值error表示各种错误,每一个二进制位的0表示出现错误,1表示未出现错误。定义下面的错误协议:

0000 0000 0000 0000 0000 0000 0000 0000 正常

0000 0000 0000 0000 0000 0000 0000 0001 蓝牙错误

0000 0000 0000 0000 0000 0000 0000 0010 电量低

0000 0000 0000 0000 0000 0000 0000 0100  gps信号弱

0000 0000 0000 0000 0000 0000 0000 1000  启动备用电池

0000 0000 0000 0000 0000 0000 0001 0000  倒地

...

如果出现多个错误就将各个错误 |起来,例如  蓝牙错误 + 电量低 +  gps信号弱,那么我们数据库存储的值就是:

0000 0000 0000 0000 0000 0000 0000 0001

|

0000 0000 0000 0000 0000 0000 0000 0010
|

0000 0000 0000 0000 0000 0000 0000 0100 

= 

0000 0000 0000 0000 0000 0000 0000 1110

转换为十进制存储到error数据就是 2 + 4 + 8 = 14;

2. 在条件搜索蓝牙错误 + 电量低的时候,将各个错误|起来得到:

0000 0000 0000 0000 0000 0000 0000 0001

|

0000 0000 0000 0000 0000 0000 0000 0010

=

0000 0000 0000 0000 0000 0000 0000 0110

,然后0000 0000 0000 0000 0000 0000 0000 0110&14 > 0 那么就是满足搜索条件的。

项目中使用的JPA的Specification来构建查询条件,但是JPA内置的查询函数是不支持位运算的。 

Specification specification = LogSpecification.newInstance(criteria);

public static Specification newInstance(LogCriteria criteria) {

        return Specification.where(LogSpecification.id(criteria.getId()))         
                .and(LogSpecification.error(criteria.getErrors()));

}

Page logs = loqRepository.findAll(specification, pagination);
解决方案

查询相关资料我们可以扩展JPA的MySQL5Dialect类,自己定义位运算的函数如下:

public class ExtendedMySQL5Dialect extends MySQL5Dialect {
    public ExtendedMySQL5Dialect() {
        super();
        // added bitwise operators
        registerFunction("bit_and", new SQLFunctionTemplate(IntegerType.INSTANCE, "(?1 & ?2)"));
        registerFunction("bit_or", new SQLFunctionTemplate(IntegerType.INSTANCE, "(?1 | ?2)"));
        registerFunction("bit_xor", new SQLFunctionTemplate(IntegerType.INSTANCE, "(?1 ^ ?2)"));
    }
}

然后配置application.yaml文件替换掉JAP默认的MySQL5Dialect:

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: com.darmi.log.ExtendedMySQL5Dialect

然后使用Specification的时候就能正常使用自定义函数了。

    public static Specification error(List errors) {
        return CollectionUtils.isEmpty(errors) ?
                (root, query, builder) -> builder.conjunction() :
                (root, query, builder) -> {
                    // convert list to integer
                    Integer res = Error.codeCompress(errors).intValue();
                    Expression errorMask = builder.literal(res);
                    // bit_and function is configured in ExtendedMySQL5Dialect
                    Expression errorFunction =
                            builder.function("bit_and", Integer.class, root.get("error"), errorMask);

                    return builder.greaterThan(errorFunction, 0);
                };
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/988041.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号