前言
实现基于postgresql,springboot,spring mvc和mybatis-plus。
核心原理是将List<T>转为JSONArray类型,数据库对应字段为json类型,即可完成存储。
实现
建表
建表SQL语句如下:
create table test.image_info (
id serial PRIMARY key NOT null,
image_address text NOT NULL,
image_owner text NOT NULL,
download_times int8 default 10,
authorized_user json,
is_deleted int8 NOT null
);
SQL 语句创建一个名为 image_info 的表,该表包含:
id
:
数据类型为 serial,这意味着它是一个自动递增的整数类型。
设置为主键(PRIMARY KEY),这意味着每一行的 id 值必须是唯一的,不能有重复。
设置为 NOT NULL,这意味着这一列的值不能为空。
image_address
:
数据类型为 text,这意味着它可以存储任意长度的文本字符串。
设置为 NOT NULL,这意味着这一列的值不能为空。
image_owner
:
数据类型为 text,这意味着它可以存储任意长度的文本字符串。
设置为 NOT NULL,这意味着这一列的值不能为空。
download_times
:
数据类型为 int8,这意味着它可以存储 8 字节的整数。
设置了默认值为 10(default 10),这意味着如果插入数据时没有为这一列提供值,那么它的值将默认为 10。
authorized_user
:
数据类型为 json,这意味着它可以存储 JSON 格式的字符串。
这一列可以用来存储有权访问该图片的用户信息,这些信息是以 JSON 格式存储的。
is_deleted
:
数据类型为 int8,这意味着它可以存储 8 字节的整数。
设置为 NOT NULL,这意味着这一列的值不能为空。
这一列通常用于标记该记录是否已被删除。例如,1 可以表示已删除,0 可以表示未删除。
通过这个 image_info 表,我们可以存储和管理图像的相关信息,如图像地址、所有者、下载次数、授权用户以及是否被删除等。
ArrayTypeHandler.java
创建List处理器,ArrayTypeHandler.java:
package org.sample.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.*;
import java.util.Arrays;
import java.util.List;
/**
*
*/
@MappedJdbcTypes(JdbcType.ARRAY)
@MappedTypes(Object.class)
public class ArrayTypeHandler extends BaseTypeHandler<Object> {
private static final String TYPE_NAME_VARCHAR = "varchar";
private static final String TYPE_NAME_INTEGER = "integer";
private static final String TYPE_NAME_BOOLEAN = "boolean";
private static final String TYPE_NAME_NUMERIC = "numeric";
private static final String TYPE_NAME_LONG = "bigint";
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
Object[] arrayObject;
if (parameter instanceof List) {
arrayObject = ((List) parameter).toArray();
} else {
arrayObject = (Object[]) parameter;
}
Connection conn = ps.getConnection();
if (arrayObject.length > 0) {
String typeName = TYPE_NAME_VARCHAR;
if (arrayObject[0] instanceof Integer) {
typeName = TYPE_NAME_INTEGER;
} else if (arrayObject[0] instanceof String) {
typeName = TYPE_NAME_VARCHAR;
} else if (arrayObject[0] instanceof Boolean) {
typeName = TYPE_NAME_BOOLEAN;
} else if (arrayObject[0] instanceof Double) {
typeName = TYPE_NAME_NUMERIC;
} else if (arrayObject[0] instanceof Long) {
typeName = TYPE_NAME_LONG;
}
Array array = conn.createArrayOf(typeName, arrayObject);
ps.setArray(i, array);
} else {
ps.setArray(i, null);
}
}
@Override
public List<Object> getNullableResult(ResultSet resultSet, String s) throws SQLException {
return getArray(resultSet.getArray(s));
}
@Override
public List<Object> getNullableResult(ResultSet resultSet, int i) throws SQLException {
return getArray(resultSet.getArray(i));
}
@Override
public List<Object> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return getArray(callableStatement.getArray(i));
}
private List<Object> getArray(Array array) {
if (array == null) {
return null;
}
try {
return Arrays.asList((Object[]) array.getArray());
} catch (Exception e) {
}
return null;
}
}
自定义的 MyBatis 类型处理器 ArrayTypeHandler,它继承自 BaseTypeHandler。这个类型处理器主要用于处理 Java 数组或 List 与数据库中的数组类型(如 PostgreSQL 的 ARRAY 类型)之间的转换:
@MappedJdbcTypes(JdbcType.ARRAY)
:表示这个类型处理器用于处理 JdbcType.ARRAY
类型的数据。
@MappedTypes(Object.class)
:表示这个类型处理器可以处理 Object 类型的数据。
setNonNullParameter
方法:
这个方法在插入或更新数据时被调用,将 Java 数组或 List 转换为数据库中的 ARRAY 类型。首先判断传入的参数 parameter 是 List 还是数组,并将其转换为 Object[] 类型的 arrayObject。
根据 arrayObject[0] 的类型确定数据库中 ARRAY 类型的元素类型,并创建一个对应类型的 Array 对象。使用 PreparedStatement 的 setArray 方法将 Array 对象设置到 SQL 语句的相应位置。
getNullableResult
方法:
这些方法在查询数据时被调用,将数据库中的 ARRAY 类型转换为 Java 数组或 List。分别针对 ResultSet
和 CallableStatement
提供了三个重载版本的 getNullableResult
方法。
所有这些方法都调用了私有方法 getArray,并将返回的数组转换为 List。
getArray 方法:这个私有方法负责从给定的 Array 对象中获取实际的数组数据。
如果 Array 对象为 null,则返回 null。否则,调用 Array.getArray
方法获取实际的数组,并将其转换为 List 返回。
ArrayTypeHandler
类主要用于在 MyBatis 中处理 Java 数组或 List 与数据库中的 ARRAY 类型之间的转换,使得 MyBatis 能够正确地将数组或 List 数据存入数据库以及从数据库中读取数组或 List 数据。
ImageInfo
我们有entity ImageInfo.java如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName(value = "test.image_info ")
public class ImageInfo implements Serializable {
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "image_address")
private String imageAddress;
@TableField(value = "image_owner")
private String imageOwner;
@TableField(value = "download_times")
private int downloadTimes;
@TableField(value = "authorized_user", typeHandler = ArrayTypeHandler.class)
private JSON authorizedUser;
@TableField(value = "is_deleted")
private int isDeleted;
}
实现
核心实现过程:
// 创建entity
List<String> finalAuthorizedUsers = authorizedUsers;
ImageInfo imageInfo = new ImageInfo();
imageInfo.setId(0L);
imageInfo.setImageOwner(username);
imageInfo.setAllowDownloadTimes(imageDownloadTimes);
imageInfo.setAuthorizedUser(finalAuthorizedUsers);
imageInfo.setIsDeleted(IsDeletedEnum.NO.getCode());
imageInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
imageInfo.setCreateUser(username);
imageInfo.setUpdateUser(username);
// 插入数据库
int insert = imageInfoServiceMapper.insert(imageInfo);