Implementing Postgres UUID primary keys with Spring Boot and Hibernate
An alternative to auto-increment sequential primary keys, is using a Universally Unique Identifier. Spring Boot and Hibernate support them and you can use them using Spring Data’s autogenerated SQL, JPQL and native queries.
As a demonstration project, you can clone spring-boot-hibernate-postgres-uuids.
To run the examples, you’ll need docker and docker-compose installed. You can setup the project by running docker-compose up in the docker directory. Doing this will create a new database, and automatically install the uuid-ossp extension.
Creating the Entity model
The project uses a User model as an example. You can setup Hibernate to use a UUID for its entity ID by using the annotations below.
@Entity
@Table(name = "users", schema = "spring_boot_uuids", uniqueConstraints = {
        @UniqueConstraint(columnNames = "email", name = "UNIQUE_EMAIL")
})
public class User
{
    @Id
    @Column
    @Type(type="pg-uuid")
    @GenericGenerator(name = "uuid-gen", strategy = "uuid2")
    @GeneratedValue(generator = "uuid-gen")
    private UUID id;
    [snip]
}Creating the Spring Data Repository
You can create a CrudRepository using a UUID as the identifier.
@Repository
public interface UserRepository extends CrudRepository<User, UUID>
{
    [snip]
}Now you can use the CrudRepository autogenerated retrieve functions.
    @Test
    public void savesUserWithId()
    {
        User user = new User();
        user.setEmail(TEST_EMAIL_ADDRESS);
        User persistedUser = userRepository.save(user);
        assertThat(persistedUser.getId(), is(not(nullValue())));
    }If you create a projection, it will work with that too.
public interface UserDisplay
{
    UUID getId();
    String getEmail();
    @Value("#{T(java.time.Period).between(target.dateOfBirth, T(java.time.LocalDate).now()).getYears()}")
    Integer getAge();
}You can use the projection in combination with a JPQL query,
    @Query("SELECT u.id AS id, " +
           "u.email AS email, " +
           "u.dateOfBirth AS dateOfBirth " +
           "FROM User u WHERE u.id = :userId")
    Optional<UserDisplay> getDisplayById(@Param("userId") UUID userId);and a native query:
    @Query(value = "SELECT CAST(u.id AS VARCHAR) AS id, " +
            "u.email AS email," +
            "u.date_of_birth AS dateOfBirth " +
            "FROM spring_boot_uuids.users u " +
            "WHERE u.id = :userId", nativeQuery = true)
    Optional<UserDisplay> getNativeDisplayById(@Param("userId") UUID userId);You’ll notice that the native query requires that the UUID be cast to a VARCHAR datatype. This is because currently Hibernate does not correctly recognise the raw UUID type.