扩展JPA对postgresql数据库数组字段的支持
此内容代码并未完全贴出来,代码码云地址:https://gitee.com/daifylearn/postgresql
postgresql虽然支持数组字段,但是Hibernate却不支持,这里需要特殊处理
直接使用三方依赖
直接引入Hibernate大佬Vlad Mihalcea自己写的开源库,轻松愉快
引入依赖
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>2.9.10</version>
</dependency>
自己实现
适用于有特殊的业务的需求或者不方便引入其他依赖的情况。主要代码还是依赖于Vlad Mihalcea的开源库。大佬已经完成代码实现,我们只需要抄就是了。
当然我们没必要把所有内容都抄一边,只抄自己需要的部分就可以主要涉及三部分代码:
需要自己实现的代码
这一块的代码主要在com.hi.config.array
包内
主要接口或类的作用
JavaTypeDescriptor
:JAVA对数据的描述,此接口提供了java方向值映射的描述内容。扩展的时候可以直接依赖抽象类AbstractTypeDescriptor
。
SqlTypeDescriptor
:JDBC对数据的处理,提供了一些值绑定、折叠等功能。
AbstractSingleColumnStandardBasicType
:双方桥梁的基础数据类型的定义,其是一个接口集包含了众多接口SingleColumnType
,BasicType
,
StringRepresentableType
,ProcedureParameterExtractionAware
,ProcedureParameterNamedBinder
。主要提供了对基础数据类型的值绑定等操作,
当然大部分内容在AbstractSingleColumnStandardBasicType
中已经有部分实现,节省了很多自己实现的动作。
使用demo
这里是使用了hibernate-types-52
的操作方式,当然自己实现的时候也是一样的内容
添加依赖
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>2.9.10</version>
</dependency>
数据模型新建
java数据模型
@Data
@Entity
@TypeDefs({
@TypeDef(name = "string-array",typeClass = StringArrayType.class)
})
public class ArrayBean {
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@Type(type = "string-array")
@Column(columnDefinition = "text[]")
private String[] authorName;
}
在实体对象类上需要声明使用的特殊类型的名称和对应类@TypeDef
,在对应属性上使用@Type
声明类型名称,同时指定数组内元素类型columnDefinition
生成的建表语句
CREATE TABLE public.array_bean (
id varchar(255) NOT NULL,
author_name text[] NULL,
"name" varchar(255) NULL,
CONSTRAINT array_bean_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
) ;
数据查询
JPA格式
这个是用可以使用JPA命名规则来实现相关查询。但是需要注意,JPA并不能很好的完成数组字段的筛选和判断。
public interface ArrayBeanRepository extends JpaRepository<ArrayBean,String> {
List<ArrayBean> findByAuthorName(String[] authorName);
}
上面的方法转化为SQL等价于下面的内容,只能进行简单的等于、不等于判断。
SELECT * FROM public.array_bean x
where array['a','b'] = x.author_name
这里需要严格匹配不仅对数组对象的元素值进行严格匹配,对顺序需要一致。但是很多时候对于数组内的数据,而postgresql针对数组参数的筛选有更加丰富的语法,
所以如果我们希望有更加灵活的方式来进行匹配。这里需要使用原生SQL来实现相关内容。
使用@Query在方法中使用原生SQL
/**
* @param authorName
* @return
*/
@Query(value = "SELECT * FROM public.array_bean x where CAST(string_to_array(?1,',') as text[]) && x.author_name",nativeQuery = true)
List<ArrayBean> findByAuthorNameIn2(String authorName);
使用EntityManager进行原生SQL查询
@Service
public class ArrayBeanServiceImpl {
@Autowired
private EntityManager em;
public List findArrayBeanByAuthorNameIn(List<String> authorName) {
StringBuffer sql = new StringBuffer("SELECT * FROM public.array_bean x");
String ids = authorName.stream().map(item -> "'" + item + "'").collect(Collectors.joining(","));
sql.append(" where CAST(array[").append(ids).append("] as text[]) && x.author_name");
Query query = em.createNativeQuery(sql.toString(),ArrayBean.class);
List<ArrayBean> resultList = query.getResultList();
ArrayBean arrayBean = resultList.get(0);
System.out.println(arrayBean.getAuthorName());
return resultList;
}
}
上面两种方式都可以实现类似查询
SELECT * FROM public.array_bean x where CAST(string_to_array('a,b,c',',') as text[]) && x.author_name
不过使用@Query方式在某些SQL中进行值替换的时候需要将数组类型转换为字符串类型进行处理。
postgresql数组类字段的支持
数组间的判断
符号 | 作用 | 例子 | 返回值 | 详细介绍 |
---|---|---|---|---|
= | 等于 | ARRAY[1,2,3]::int[] = ARRAY[1,2,3] | true | 等于判断需要两个数组在内容上和顺序上严格相同 |
<> | 不等于 | ARRAY[1,2,3] <> ARRAY[1,2,4] | true | 和=判断相反 |
< | 小于 | ARRAY[1,2,3] < ARRAY[1,2,4] | true | 根据数组元素进行依次判断每个元素大小 |
> | 大于 | ARRAY[1,4,3] > ARRAY[1,2,4] | true | 根据数组元素进行依次判断每个元素大小 |
<= | 小于或等于 | ARRAY[1,2,3] <= ARRAY[1,2,3] | true | 根据数组元素进行依次判断每个元素大小 |
>= | 大于或等于 | ARRAY[1,4,3] >= ARRAY[1,4,3] | true | 根据数组元素进行依次判断每个元素大小 |
@> | 包含 | ARRAY[1,4,3] @> ARRAY[3,1] | true | 右侧元素中要全部出现在左侧中,对于右侧重复的元素并不要求个数相同,如:ARRAY[1,4,3] @> ARRAY[3,1,1] 也会返回true |
<@ | 被包含于 | ARRAY[2,7] <@ ARRAY[1,7,4,2,6] | true | 和@>相反,需要左侧元素都出现在右侧 |
&& | 重叠(有共同元素) | ARRAY[1,4,3] && ARRAY[2,1] | true | 左右两侧有相同的元素存在 |
数组的操作
数组中添加元素使用 ||
。根据双方数据类型不同会出现三种结果
数组值合并
当两个数组使用||
时,会将其内容进行合并:
ARRAY[1,2,3] || ARRAY[4,5,6] -> {1,2,3,4,5,6}
作为数组子元素添加
如果一方是二维数组的时候,根据双方位置会将,数组添加至二维数组的头节点或者尾节点
ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]] -> {{1,2,3},{4,5,6},{7,8,9}}
值添加进数组中
根据值位于左侧或者右侧,单一值会作为数组的头部或尾部节点添加进来
ARRAY[4,5,6] || 7 -> {4,5,6,7}
数组相关函数
函数 | 参数 | 作用 | 语法 | 对应操作符 | 结果 |
---|---|---|---|---|---|
array_append | array,element | 向数组尾部添加元素 | array_append(ARRAY[1,2], 3) | || | {1,2,3} |
array_prepend | element,array | 向数组头部添加元素 | array_append(3,ARRAY[1,2]) | || | {3,1,2} |
array_cat | array,array | 合并两个数组元素 | array_cat(ARRAY[1,2,3], ARRAY[4,5]) | || | {1,2,3,4,5} |
array_dims | array | 用来返回数组的上届和下届,当是多维数组的时候会依次显示其范围(下界默认1开始) | array_dims(ARRAY[[1,2,3], [4,5,6]]) | [1:2][1:3] | |
array_lower | array,int(数组的维数) | 返回指定维数的下界 | array_lower(ARRAY[[1,2,3], [4,5,6]],2) | 1 | |
array_upper | array,int(数组的维数) | 返回指定维数的上界 | array_upper(ARRAY[1,2,3,4], 1) | 4 | |
array_to_string | array,text | 使用指定的分隔符将数组转换为字符串 | array_to_string(ARRAY[1, 2, 3], ‘,’) | 1,2,3 | |
string_to_array | text… | 将指定的字段将字符串切分为数组 | select string_to_array(‘a-b-c’,’-’) | ARRAY[‘a’,‘b’,‘c’] | {a,b,c} |