Grails 內建的 GORM(Grails Object Relational Mapping)是建立在 Hibernate 之上的薄薄 Groovy 層,保留了 Hibernate 所有進階功能,同時提供了極具表達力的 DSL,讓持久化配置變得簡潔直觀。本文將從 ORM 基礎概念出發,逐步深入一對多關聯、資料驗證、GORM DSL、多資料庫切換等核心主題。
關係型資料庫基於集合論,而現代應用基於物件導向。兩者之間的「物件關係阻抗失配」導致資料存取充滿樣板代碼。Hibernate、TopLink、JPA 等 ORM 框架試圖填補這道鴻溝。GORM 繼承了 Hibernate 的成熟度,並以 Groovy 動態特性大幅簡化配置。
以旅行規劃網站為例,Trip 與 Airline 之間為多對一關係(一家航空公司對應多個行程)。在 Groovy 中自然以物件組合表示:
class Trip {
String name
String city
Date startDate
Date endDate
Airline airline
}
在 Airline 端宣告 hasMany 即可完成雙向關聯:
class Airline {
static hasMany = [trip: Trip]
String name
String url
String frequentFlyer
String notes
}
GORM 會自動在 trip 表建立 airline_id 外鍵,開發者無需在領域模型中暴露主鍵,避免了「抽象洩漏」。
Grails 採用「裸物件」模式:直接在領域類別添加靜態屬性(hasMany、constraints、mapping)即可配置行為,無需外部 XML。搭配控制器的 def scaffold = Airline,Grails 會動態生成 CRUD 操作與 GSP 視圖。修改領域類別後儲存,瀏覽器即時生效,無需重啟伺服器,極大提升開發效率。
實作 toString() 可讓下拉選單顯示有意義的名稱而非 ID。在 static constraints 區塊按順序列出欄位,即可控制視圖呈現順序:
static constraints = {
name()
url()
frequentFlyer()
notes()
}
constraints 區塊同時支援視圖層與持久層驗證。常見規則包括:
blank:false 必填maxSize:100 長度限制(影響資料庫欄位長度)url:true 格式驗證email:true、matches:/regex/ 等static constraints = {
name blank: false, maxSize: 100
url url: true
frequentFlyer blank: true
notes maxSize: 1500
}
驗證失敗時會自動在視圖顯示錯誤訊息,訊息可在 grails-app/i18n/messages.properties 客製化並支援多語系。
透過 static mapping 區塊可覆寫表名、欄位名、資料型別、主鍵策略、快取設定等,所有配置集中在領域類別內:
static mapping = {
table 'airline_master'
columns {
name column: 'airline_name'
url column: 'link'
frequentFlyer column: 'ff_id'
}
cache usage: 'read-write'
}
這對整合遺留資料庫極為有用。DSL 亦支援複合主鍵、外鍵欄位自定、Hibernate 快取策略等進階功能。
所有領域類別共享的資料庫配置集中在 grails-app/conf/DataSource.groovy。核心結構包含:
dataSource 區塊:驅動、帳號、密碼、連線池設定hibernate 區塊:快取提供者等environments 區塊:development、test、production 三種模式的差異化配置關鍵屬性 dbCreate 控制 Hibernate 自動建表策略:
create-drop:啟動建表、關閉刪表(適合開發)create:需要時建表/修改表,重啟資料不保留update:保留資料並同步結構變更(生產預設)生產環境強烈建議註解掉 dbCreate,由 DBA 手動管理結構變更。可自訂環境(如 beta),啟動時指定 grails -Dgrails.env=beta run-app。
若允許 Hibernate 管理結構(dbCreate 未關閉),切換資料庫僅需三步:
lib 目錄DataSource.groovy 的驅動、連線字串、帳號密碼範例:MySQL 配置
driverClassName = "com.mysql.jdbc.Driver"
username = "grails"
password = "server"
url = "jdbc:mysql://localhost:3306/trip?autoreconnect=true"
DB2 配置
driverClassName = "com.ibm.db2.jcc.DB2Driver"
username = "db2admin"
password = "db2admin"
url = "jdbc:db2://localhost:50000/trip"
任何有 JDBC 驅動與 Hibernate 方言的資料庫皆可無縫切換。
GORM 以約定優於配置、裸物件模式、強大 DSL,讓持久化層開發回歸業務邏輯。掌握關聯映射、驗證規則、環境化資料源配置,即可輕鬆應對從原型到生產的各種場景。下一篇將聚焦 Web 層:GSP、TagLib、模板客製化等前端技術。