Java JPA 规范如何处理位操作
How Java JPA Specification works with bit operations
我正在尝试 运行 规范中的一些位操作,但文档很少。
例如,我有一个 table tb_user
和一个位 (32) 字段 roles
。我正在尝试搜索具有特定翻转位(位 = 1)的记录。假设我搜索 b'1011' 并且结果应该 return 所有翻转了 bit0 或 bit1 或 bit3 的记录。如果我搜索 b'0011' 并且结果应该 return 有 bit0、bit1 翻转的记录。
我如何在 JPA 规范中做到这一点?
public static Specification<TbUser> role(Integer roles) {
return ObjectUtils.isEmpty(roles) ?
(root, query, builder) -> builder.conjunction() :
(root, query, builder) -> {
// How do I run the bit operations?
}
}
我没有看到按位 AND 是 SQL 的一部分; JPA/JPQL 被编写为与数据库无关,因此不会内置数据库特定支持(Transact-SQL?)。
JPA 3 规范部分“4.6.17.3”有一个 'FUNCTION' 运算符,可用于将“&”应用于您的参数。 Criteria api 有一个 'function' 方法,其操作相同,但您必须提供预期的 return 类型才能在大于表达式中使用它。像
Expression<Integer> bitwiseAnd = builder.function("&", Integer.class, root.get("role"), 4);
builder.greaterThan(bitwiseAnd, 0);
在我这边
builder.function("&", Integer.class, root.get("role"), 4);
会触发错误
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '&(tb_user0_.role, 524290)>0 or &(tb_user0_.role, 524290)<0)' at line 1
所以我不能在规范中直接使用“&”。
另一种有效的方法如下:
// customize a MySQL5Dialect with new registered function
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)"));
}
}
// change your yaml or property file
spring:
application:
name: user-service
jpa:
hibernate:
ddl-auto: update
database-platform: com.package.path.ExtendedMySQL5Dialect
//implementation of specification
public static Specification<TbUser> role(Integer roles) {
return ObjectUtils.isEmpty(roles) ?
(root, query, builder) -> builder.conjunction() :
(root, query, builder) -> {
Expression<Integer> bitwiseAnd = builder.function("bit_and", Integer.class, root.get("role"), 4);
return builder.greaterThan(bitwiseAnd, 0);
}
}
我正在尝试 运行 规范中的一些位操作,但文档很少。
例如,我有一个 table tb_user
和一个位 (32) 字段 roles
。我正在尝试搜索具有特定翻转位(位 = 1)的记录。假设我搜索 b'1011' 并且结果应该 return 所有翻转了 bit0 或 bit1 或 bit3 的记录。如果我搜索 b'0011' 并且结果应该 return 有 bit0、bit1 翻转的记录。
我如何在 JPA 规范中做到这一点?
public static Specification<TbUser> role(Integer roles) {
return ObjectUtils.isEmpty(roles) ?
(root, query, builder) -> builder.conjunction() :
(root, query, builder) -> {
// How do I run the bit operations?
}
}
我没有看到按位 AND 是 SQL 的一部分; JPA/JPQL 被编写为与数据库无关,因此不会内置数据库特定支持(Transact-SQL?)。
JPA 3 规范部分“4.6.17.3”有一个 'FUNCTION' 运算符,可用于将“&”应用于您的参数。 Criteria api 有一个 'function' 方法,其操作相同,但您必须提供预期的 return 类型才能在大于表达式中使用它。像
Expression<Integer> bitwiseAnd = builder.function("&", Integer.class, root.get("role"), 4);
builder.greaterThan(bitwiseAnd, 0);
在我这边
builder.function("&", Integer.class, root.get("role"), 4);
会触发错误
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '&(tb_user0_.role, 524290)>0 or &(tb_user0_.role, 524290)<0)' at line 1
所以我不能在规范中直接使用“&”。
另一种有效的方法如下:
// customize a MySQL5Dialect with new registered function
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)"));
}
}
// change your yaml or property file
spring:
application:
name: user-service
jpa:
hibernate:
ddl-auto: update
database-platform: com.package.path.ExtendedMySQL5Dialect
//implementation of specification
public static Specification<TbUser> role(Integer roles) {
return ObjectUtils.isEmpty(roles) ?
(root, query, builder) -> builder.conjunction() :
(root, query, builder) -> {
Expression<Integer> bitwiseAnd = builder.function("bit_and", Integer.class, root.get("role"), 4);
return builder.greaterThan(bitwiseAnd, 0);
}
}