使用 JPA 在 PostgreSQL 中持久保存 UUID

在使用 PostgreSQL 构建强大的 Java应用程序时,处理唯一标识符是一项基本要求。UUID(通用唯一标识符)提供了一种绝佳的替代方案,而不是依赖自动递增的数字 ID ,尤其是在分布式系统中。

随着时间的推移, 在 Java 应用程序中生成 UUID 作为主键已经变得非常普遍。在本教程中,我们将探讨如何使用 JPA(Java 持久性 API)在 PostgreSQL 中持久化 UUID,重点介绍实际实现,并提供一个在应用程序中管理用户的相关示例。

在本文中,我们介绍了使用 JPA 在 PostgreSQL 中保留 UUID 的基本步骤。

我们首先设置 PostgreSQL 并集成 JPA,以在应用程序和数据库之间建立连接。接下来,我们通过在 PostgreSQL 中定义 UUID 列并将其映射到实体类中作为主键,为 UUID 支持配置 JPA。

然后,我们演示了如何使用 JPA 存储库高效地存储和检索 UUID。最后,我们通过测试 UUID 持久性来验证实现。所有这些步骤确保应用程序保持可扩展性和安全性,并遵循现代最佳实践。

设置 PostgreSQL 和 JPA
在深入了解配置细节之前,让我们确保我们的开发环境已准备就绪。首先,我们需要一个 PostgreSQL 数据库。然后,我们将使用应用程序所需的 Maven 依赖项和 PostgreSQL 相关属性设置我们的 Spring Boot 项目。

Maven 依赖项
要开始使用 PostgreSQL,我们将驱动程序依赖项添加 到我们的 pom.xml 文件中:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>

此依赖项添加了 PostgreSQL JDBC 驱动程序,使我们的应用程序能够连接并与数据库通信。它确保了我们的 Java 应用程序与 PostgreSQL 之间的兼容性。

接下来,我们还需要添加spring-data-jpa 依赖项 :

<dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-jpa</artifactId>
</dependency>

此依赖项引入了 Hibernate、Spring Data JPA 和其他实用程序,使我们能够使用对象关系映射 (ORM) 与关系数据库进行交互。它还简化了常见的数据库操作,而无需自定义 SQL 查询。

PostgreSQL 配置
要配置数据源,让我们在application.properties文件中添加必要的属性:

spring.datasource.url=jdbc:postgresql://localhost:5432/user_management
spring.datasource.username=username
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

此配置块通过指定数据库详细信息(如 URL、名称、身份验证凭据和 Hibernate 设置)帮助我们的 Spring Boot 应用程序连接到 PostgreSQL 数据库。

为 UUID 配置 JPA
现在我们的开发环境已经准备就绪,让我们专注于配置 JPA 以有效地处理 UUID。我们将在 PostgreSQL 中映射 UUID 列并将其与我们的 JPA 实体集成。

PostgreSQL 中的 UUID 列
在 PostgreSQL 中,UUID类型原生支持 128 位通用唯一标识符,使其成为确保主键唯一性的绝佳选择,尤其是在分布式系统中。

考虑在应用程序中管理用户的示例,让我们创建一个名为用户的表,其中我们利用UUID 作为主键:

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE
);

这种结构确保每个用户都有全局唯一的标识符,从而消除了不同系统之间密钥冲突的风险。gen_random_uuid()函数在每次插入记录时默认为id列生成一个新的随机 UUID ,从而简化了分配唯一主键的任务。

实体类
现在让我们创建一个 JPA 实体来映射用户表中的行:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(columnDefinition =
"uuid", updatable = false, nullable = false)
    private UUID id;
    @Column(nullable = false)
    private String username;
    @Column(nullable = false, unique = true)
    private String email;
   
// Getters and Setters
}

这里,id字段用@Id和@GeneratedValue注释,表示它是主键,其值将自动生成为 UUID。我们还使用 columnDefinition将此列专门声明为uuid。

用户名和电子邮件字段映射到各自的列并标记为@Column。电子邮件字段也被标记为唯一 ,以确保表中不允许重复的电子邮件条目。

存储库和服务类
接下来,让我们实现一个存储库来与数据库交互,以及一个服务层来封装用于管理用户实体的业务逻辑。

UserRepository将处理数据库操作:

public interface UserRepository extends JpaRepository<User, UUID> {
}

UserRepository扩展了JpaRepository ,为常见的数据库操作(如保存、查找和删除实体)提供了内置方法。

UserService 提供了管理用户的业务逻辑:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    public User createUser(String name, String email) {
        User user = new User();
        user.setName(name);
        user.setEmail(email);
        return userRepository.save(user);
    }
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    public User getUserById(UUID id) {
        return userRepository.findById(id).orElse(null);
    }
}

UserService 封装了业务逻辑,与存储库交互来处理与用户相关的操作,例如保存新用户和通过 UUID 检索现有用户。

测试UUID持久性
我们将添加并执行UserRepository的测试,以确保在使用 UUID 保存和检索用户时能够正常运行。我们还将验证已保存实体的ID是否为有效的 UUID。

首先,让我们添加一个测试来通过UserRepository保存用户:

@DataJpaTest
public class UserRepositoryTest {
    @Autowired
    private UserRepository userRepository;
    @Test
    public void givenUserEntity_whenSaved_thenIdIsUUID() {
        // Create and save a User entity
        User user = new User();
        user.setName(
"Alice");
        user.setEmail(
"alice@example.com");
       
// Save the user to the database
        User savedUser = userRepository.save(user);
       
// Verify the saved entity has a valid UUID
        assertThat(savedUser.getId()).isNotNull();
        assertThat(savedUser.getId()).isInstanceOf(UUID.class);
    }
}

接下来,让我们在同一个类中添加另一个测试来通过 ID 检索用户:

@Test
public void givenSavedUser_whenFindById_thenUserIsRetrieved() {
    // Save a user
    User user = new User();
    user.setName(
"Jane Smith");
    user.setEmail(
"jane.smith@example.com");
    User savedUser = userRepository.save(user);
   
// Retrieve the user by ID
    Optional<User> retrievedUser = userRepository.findById(savedUser.getId());
   
// Verify the user is retrieved correctly
    assertThat(retrievedUser).isPresent();
    assertThat(retrievedUser.get().getId()).isEqualTo(savedUser.getId());
    assertThat(retrievedUser.get().getName()).isEqualTo(
"Jane Smith");
    assertThat(retrievedUser.get().getEmail()).isEqualTo(
"jane.smith@example.com");
   
// Verify the Id is UUID
    assertThat(retrievedUser.get().getId()).isNotNull();
    assertThat(retrievedUser.get().getId()).isInstanceOf(UUID.class);
}

通过这些测试,我们确保我们的应用程序可以使用基于 UUID 的主键可靠地存储和检索用户,从而确认 JPA 与 PostgreSQL 的 UUID 功能的集成。