• 自定义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内置的查询函数是不支持位运算的。 

    1. Specification<Log> specification = LogSpecification.newInstance(criteria);
    2. public static Specification<Log> newInstance(LogCriteria criteria) {
    3. return Specification.where(LogSpecification.id(criteria.getId()))
    4. .and(LogSpecification.error(criteria.getErrors()));
    5. }
    6. Page<Log> logs = loqRepository.findAll(specification, pagination);

    解决方案

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

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

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

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

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

    1. public static Specification<TbVehicle> error(List<Integer> errors) {
    2. return CollectionUtils.isEmpty(errors) ?
    3. (root, query, builder) -> builder.conjunction() :
    4. (root, query, builder) -> {
    5. // convert list to integer
    6. Integer res = Error.codeCompress(errors).intValue();
    7. Expression<Integer> errorMask = builder.literal(res);
    8. // bit_and function is configured in ExtendedMySQL5Dialect
    9. Expression<Integer> errorFunction =
    10. builder.function("bit_and", Integer.class, root.get("error"), errorMask);
    11. return builder.greaterThan(errorFunction, 0);
    12. };
    13. }

  • 相关阅读:
    Android13 下载apk并安装apk
    pytorch之nn.Conv1d详解
    从0实现线性回归
    ctf-pikachu-file_download
    Rust 构建开源 Pingora 框架可以与nginx媲美
    jQuery获取表单的值val()
    Spring Cloud学习(九)【Elasticsearch 分布式搜索引擎01】
    【Shell 系列教程】Shell printf 命令( 六)
    .NET 6学习笔记(7)——ASP.NET Core通过配置文件启用HTTPS
    STL-stack、queue和priority_queue的模拟实现
  • 原文地址:https://blog.csdn.net/qq_28175019/article/details/125435997