數據庫關鍵字作為 Hibernate 實體中的列
一、概述
在本教程中,我們將學習如何通過正確轉義列名中的數據庫關鍵字來避免神秘的 Hibernate 異常。
2.設置
在我們深入之前,讓我們定義一個簡單的BrokenPhoneOrder
實體,在列映射中使用保留關鍵字:
@Entity
public class BrokenPhoneOrder implements Serializable {
@Id
@Column(name = "order")
String order;
@Column(name = "where")
String where;
<code class="language-sql">// getters and setters
一旦我們了解了該實體導致的語法異常的原因,我們就會將它變成一個沒有使用有缺陷的數據庫關鍵字的PhoneOrder
。
2. Hibernate 異常——隱藏的根本原因
讓我們想像一下,從我們基於 ORM 的應用程序接收到以下異常:
You have an error <span class="hljs-keyword">in</span> your <span class="hljs-keyword">SQL</span> syntax; <span class="hljs-keyword">check</span> the manual that corresponds <span class="hljs-keyword">to</span> your MySQL server version <span class="hljs-keyword">for</span> the <span class="hljs-keyword">right</span> syntax
當我們嘗試將BrokenPhoneOrder
持久化到數據庫時,它總是被拋出:
@Test
void givenBrokenPhoneOrderWithReservedKeywords_whenNewObjectIsPersisted_thenItFails() {
BrokenPhoneOrder order = new BrokenPhoneOrder(randomUUID().toString(), "My House");
assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> {
session.persist(order);
session.flush();
});
}
異常本身沒有用,所以讓我們啟用額外的 SQL 語句日誌記錄來訪問實際查詢。
我們需要修改hibernate.cfg.xml
以包含show_sql
屬性:
<property name="show_sql">true</property>
對於hibernate.properties,
語法略有不同:
show_sql = true
現在我們可以看到在異常日誌之前記錄了以下 SQL 語句:
Hibernate:插入 broken_phone_order(where,order)值(?,?)
問號只是order
的值以及我們試圖創建的BrokenPhoneOrder
實體的where
。
3.實際的SQL錯誤
我們可能已經能夠找出異常的根本原因。但即使沒有,讓我們選擇我們最喜歡的 SQL 編輯器並將捕獲的 SQL 與示例值粘貼在一起:
INSERT INTO broken_phone_order (order, where) VALUES ('some-1', 'somewhere');
在大多數情況下,我們會看到已經用紅色標記的where
和order
。如果沒有,一旦我們執行它,數據庫引擎(在我們的例子中是 MySQL)返回一個錯誤:
ERROR 1064 (42000): 你的 SQL 語法有錯誤;檢查與您的 MySQL 服務器版本對應的手冊,了解在第 1 行的“order, where) values ('a', 'b')' 附近使用的正確語法
4. 數據庫關鍵詞
根據 SQL 標準, ORDER
和WHERE
都是保留字。因此,它們在語言語法中具有特殊的含義。每個數據庫引擎都有相同的基本單詞列表,但也可以對其進行擴展。
我們可以簡單地通過用“
字符包裹它們來刪除特殊含義,例如, `where`
。
讓我們將它應用到INSERT
語句並確認這次它通過了:
INSERT INTO broken_phone_order (`order`, `where`) VALUES ('some-1', 'somewhere');
5. Hibernate 中的保留字
問題是:如果 Hibernate 查詢是自動生成的,我們將如何更改它?
在 Hibernate 中,就像在 SQL 中一樣,我們可以簡單地在@Column
註釋中使用“
轉義”。
讓我們嘗試使用PhoneOrder
實體:
@Entity
@Table(name = "phone_order")
public class PhoneOrder implements Serializable {
@Id
@Column(name = "`order`")
String order;
@Column(name = "`where`")
String where;
// getters and setters
}
通過適當的關鍵字轉義,MySQL 不再抱怨語法,實體成功持久化:
@Test
void givenPhoneOrderWithEscapedKeywords_whenNewObjectIsPersisted_thenItSucceeds() {
PhoneOrder order = new PhoneOrder(randomUUID().toString(), "here");
session.persist(order);
session.flush();
}
六,結論
在本文中,我們學習瞭如何正確轉義@Column
註釋中的保留字。通過order
和where
術語周圍添加額外的轉義字符,我們影響了 Hibernate 生成的查詢並解決了異常。
與往常一樣,可以在 GitHub 上找到本文的代碼。