• 自定义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. }

  • 相关阅读:
    持续集成交付CICD:Jenkins Sharedlibrary 共享库
    微信小程序自定义组件数据、方法和属性
    Flutter:getX的学习
    1024程序员节特色海报两张
    移相全桥DCDC通过Simulink扫频得到其传递函数方法及(非m脚本)
    测试Bard和ChatGPT关于双休的法规和推理
    Java IO流
    java(Collections工具类)
    基于openEuler虚拟机远端执行mugen测试脚本
    分享几个Google Chrome谷歌浏览器历史版本下载网站
  • 原文地址:https://blog.csdn.net/qq_28175019/article/details/125435997