如何修復 PSQLException:運算子不存在:字元變化 = UUID
一、簡介
在本教學中,我們將探討使用 JPA 與 PostgreSQL 互動時出現的PSQLException
錯誤:「 operator does not exist: character varying = uuid
」。我們將深入研究發生此錯誤的原因,確定觸發該錯誤的常見情況,並了解如何解決該錯誤。
2. 異常原因
PostgreSQL 區分字元變化(字串)和 UUID 資料類型。這種差異需要顯式類型轉換或轉換才能在這些類型之間進行比較。因此,當我們嘗試直接將 UUID 值與字串 ( VARCHAR
) 欄位進行比較時,PostgreSQL 會引發異常,因為它缺少用於這種特定類型比較的運算子。
讓我們考慮一個範例,其中有一個帶有varchar
列uuid
的User
實體:
@Entity
@Table(name = "User_Tbl")
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(columnDefinition = "varchar")
private UUID uuid;
// getters and setters
}
當我們嘗試使用 UUID 值查詢資料庫時,我們收到錯誤:
UUID testId = UUID.fromString("c3917b5b-18ed-4a84-a6f7-6be7a8c21d66");
User user = new User();
user.setUuid(testId);
user.setName("John Doeee");
userRepository.save(user);
Throwable throwable = assertThrows(InvalidDataAccessResourceUsageException.class,
() -> userRepository.findByUuid(testId),
"Expected ERROR: operator does not exist: character varying = uuid");
assertTrue(getRootCause(throwable) instanceof PSQLException);
3.修復異常
為了解決這個問題,我們需要確保正確處理字元變化和 UUID 值之間的比較。讓我們看看推薦的方法。
3.1.使用CAST()
函數
我們可以使用 PostgreSQL 中的CAST()
函數將 UUID 值明確轉換為 JPA 查詢中的字串。
CAST()
函數是一個內建的 PostgreSQL 函數,它允許我們將一種資料類型的值轉換為另一種資料類型。這可確保 PostgreSQL 正確處理 UUID 值和varchar
類型之間的比較。
以下是如何修復查詢的範例:
@Query("SELECT u FROM User u WHERE u.uuid = CAST(:uuid AS text)")
Optional<User> findByUuidWithCastFunction(@Param("uuid") UUID uuid);
透過將字元變化值轉換為 UUID,我們確保資料庫可以正確執行比較:
UUID testId = UUID.fromString("c3917b5b-18ed-4a84-a6f7-6be7a8c21d66");
Optional<User> userOptional = userRepository.findByUuidWithCastFunction(testId);
assertThat(userOptional.isPresent(), is(true));
assertThat(userOptional.get().getUuid(), equalTo(testId));
讓我們觀察產生的 SQL 查詢,包括CAST(:id AS text)
操作:
Hibernate:
select
user0_.id as id1_0_,
user0_.name as name2_0_,
user0_.uuid as uuid3_0_
from
user_tbl user0_
where
user0_.uuid=cast(? as text)
cast(? as text)
顯示了使用CAST()
函數將 UUID 參數轉換為文字類型,確保與 PostgreSQL 中的varchar
列相容。
3.2.使用自訂轉換器
除了使用 SQL 函數直接轉換之外,我們還可以使用 JPA 中的@Converter
註解為UUID
物件和varchar
列定義自訂轉換器。此轉換器有助於UUID
物件與其在資料庫中的字串表示形式之間的無縫轉換。
首先,讓我們實作UUIDConverter
類,實作AttributeConverter<UUID, String>
:
@Converter
public class UUIDConverter implements AttributeConverter<UUID, String> {
@Override
public String convertToDatabaseColumn(UUID uuid) {
return uuid.toString();
}
@Override
public UUID convertToEntityAttribute(String dbData) {
return UUID.fromString(dbData);
}
}
接下來,我們可以在 JPA 實體中的UUID
欄位上使用@Convert
註解:
@Entity
public class UserWithConverter{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Convert(converter = UUIDConverter.class)
@Column(columnDefinition = "varchar")
private UUID uuid;
// getters and setters
}
@Convert
註解將 JPA 配置為在將實體持久保存到資料庫時自動將UUID
欄位轉換為字串 ( VARCHAR
) 類型,反之亦然。
Optional<UserWithConverter> userOptional = userWithConverterRepository.findByUuid(testId);
assertThat(userOptional.isPresent(), is(true));
assertThat(userOptional.get().getUuid(), equalTo(testId));
4。
在本文中,我們討論了PSQLException
“ operator does not exist: character varying = uuid
”以及如何透過將 UUID 值明確轉換為字元變化或使用 JPA 中的自訂轉換器來修復它。
與往常一樣,範例的原始程式碼可在 GitHub 上取得。