1. 概述
PostgreSQL 支持将任何类型(内置或用户定义)的数组定义为表的列类型 。在本教程中,我们将探索使用Hibernate映射 PostgreSQL 数组的几种方法。
2. 基本设置
作为连接 PostgreSQL 数据库的先决条件,我们应该将最新的 postgresql Maven 依赖项与 Hibernate 配置一起添加到 pom.xml 中。另外,让我们使用 字符串 数组 Roles 创建一个名为 User 的实体类:
@Entity
public class User {
@Id
private Long id;
private String name;
private String[] roles;
//getters and setters
}
3. 自定义 Hibernate 类型
Hibernate 支持自定义类型以将用户定义的类型映射到 SQL 查询。因此, 我们可以创建自定义类型来将 PostgreSQL 数组映射到 Hibernate 来存储/获取数据。首先,我们创建 CustomStringArrayType 类来实现 Hibernate 的 UserType 类,以提供自定义类型来映射 String 数组:
public class CustomStringArrayType implements UserType<String[]> {
@Override
public int sqlType() {
return Types.ARRAY;
}
@Override
public Class returnedClass() {
return String[].class;
}
@Override
public String[] nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session,
Object owner) throws SQLException {
Array array = rs.getArray(position);
return array != null ? (String[]) array.getArray() : null;
}
@Override
public void nullSafeSet(PreparedStatement st, String[] value, int index,
SharedSessionContractImplementor session) throws SQLException {
if (st != null) {
if (value != null) {
Array array = session.getJdbcConnectionAccess().obtainConnection()
.createArrayOf("text", value);
st.setArray(index, array);
} else {
st.setNull(index, Types.ARRAY);
}
}
}
//implement equals, hashCode, and other methods
}
这里需要注意的是 returnedClass 方法的返回类型是 String 数组 。此外, nullSafeSet 方法创建一个 PostgreSQL 类型 text 的数组 。
4. 使用自定义 Hibernate 类型映射数组
4.1. 用户 实体
然后,我们将使用 CustomStringArrayType 类将 字符串 数组 角色 映射到 PostgreSQL 文本 数组:
@Entity
public class User {
//...
@Column(columnDefinition = "text[]")
@Type(value = com.baeldung.hibernate.arraymapping.CustomStringArrayType.class)
private String[] roles;
//getters and setters
}
就是这样!我们已准备好使用自定义类型实现和数组映射来对 User 实体执行 CRUD 操作。
4.2.单元测试
为了测试我们的自定义类型,我们首先插入一个 User 对象以及 String 数组 Roles :
@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB()
throws HibernateException, IOException {
transaction = session.beginTransaction();
User user = new User();
user.setId(2L);
user.setName("smith");
String[] roles = {"admin", "employee"};
user.setRoles(roles);
session.persist(user);
session.flush();
session.clear();
transaction.commit();
User userDBObj = session.find(User.class, 2L);
assertEquals("smith", userDBObj.getName());
assertEquals("admin", userDBObj.getRoles()[0]);
assertEquals(578, userDBObj.getLocations()[1]);
}
此外,我们还可以以 PostgreSQL 文本 数组的形式获取包含 角色 的用户 记录:
@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB()
throws HibernateException, IOException {
User user = session.find(User.class, 2L);
assertEquals("john", user.getName());
assertEquals("superuser", user.getRoles()[0]);
assertEquals("employee", user.getRoles()[1]);
assertEquals("admin", user.getRoles()[1]);
assertEquals(100, user.getLocations()[0]);
assertEquals(389, user.getLocations()[1]);
assertEquals("7000000000", user.getPhoneNumbers()[0]);
assertEquals("8000000000", user.getPhoneNumbers()[1]);
}
4.3. 自定义整数数组类型
同样,我们可以为 PostgreSQL 支持的各种数组类型创建自定义类型。例如,让我们创建 CustomIntegerArrayType 来映射 PostgreSQL int 数组:
public class CustomIntegerArrayType implements UserType<Integer[]> {
@Override
public int sqlType() {
return Types.ARRAY;
}
@Override
public Class returnedClass() {
return Integer[].class;
}
@Override
public Integer[] nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session,
Object owner) throws SQLException {
Array array = rs.getArray(position);
return array != null ? (Integer[]) array.getArray() : null;
}
@Override
public void nullSafeSet(PreparedStatement st, Integer[] value, int index,
SharedSessionContractImplementor session) throws SQLException {
if (st != null) {
if (value != null) {
Array array = session.getJdbcConnectionAccess().obtainConnection().createArrayOf("int", value);
st.setArray(index, array);
} else {
st.setNull(index, Types.ARRAY);
}
}
}
//implement equals, hashCode, and other methods
}
与我们在 CustomStringArrayType 类中注意到的类似, returnedClass 方法的返回类型是 Integer array 。此外, nullSafeSet 方法的实现会创建一个 PostgreSQL 类型 int 的数组 。最后,我们可以使用 CustomIntegerArrayType 类将 Integer 数组 位置 映射到 PostgreSQL int 数组:
@Entity
public class User {
//...
@Column(columnDefinition = "int[]")
@Type(value = com.baeldung.hibernate.arraymapping.CustomIntegerArrayType.class)
private Integer[] locations;
//getters and setters
}
5. 使用 hibernate-types 映射数组
另一方面,我们可以使用由著名 Hibernate 专家 Vlad Mihalcea 开发的 hibernate-types 库,而不是为每种类型(如 String 、 Integer 和 Long )实现自定义类型。
5.1.设置
首先,我们将最新的 hibernate-types-60 Maven 依赖项添加到 pom.xml 中:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-60</artifactId>
<version>2.21.1</version>
</dependency>
5.2. 用户 实体
接下来,我们将在 User 实体中添加集成代码以映射 字符串 数组 phoneNumbers :
@Entity
public class User {
//...
@Type(StringArrayType.class)
@Column(
name = "phone_numbers",
columnDefinition = "text[]"
)
private String[] phoneNumbers;
//getters and setters
}
在这里,与自定义类型 CustomStringArrayType 类似,我们使用 hibernate-types 库提供的 StringArrayType 类作为 String 数组的映射器。同样,我们可以 在库中找到其他一些方便的映射器,例如 DateArrayType 、 EnumArrayType 和 DoubleArrayType 。
5.3.单元测试
就是这样!我们已准备好使用 hibernate-types 库进行数组映射。让我们更新已经讨论过的单元测试来验证插入操作:
@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB()
throws HibernateException, IOException {
transaction = session.beginTransaction();
User user = new User();
user.setId(2L);
user.setName("smith");
String[] roles = {"admin", "employee"};
user.setRoles(roles);
String[] phoneNumbers = {"7000000000", "8000000000"};
user.setPhoneNumbers(phoneNumbers);
session.persist(user);
session.flush();
session.clear();
transaction.commit();
}
同样,我们可以验证读操作:
@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB()
throws HibernateException, IOException {
User user = session.find(User.class, 2L);
assertEquals("john", user.getName());
assertEquals("superuser", user.getRoles()[0]);
assertEquals("admin", user.getRoles()[1]);
assertEquals(100, user.getLocations()[0]);
assertEquals(389, user.getLocations()[1]);
assertEquals("7000000000", user.getPhoneNumbers()[0]);
assertEquals("8000000000", user.getPhoneNumbers()[1]);
}
六,结论
在本文中,我们探讨了使用 Hibernate 映射 PostgreSQL 数组。首先,我们创建了一个自定义类型来使用 Hibernate 的 UserType 类映射 String 数组。然后,我们使用自定义类型将 PostgreSQL 文本 数组与 Hibernate 进行映射。最后,我们使用 hibernate-types 库来映射 PostgreSQL 数组。与往常一样,源代码可在 GitHub 上获取。