Spring 整合 Hibernate
Posted by Bruce Tsai
Hibernate 是開發中最常見的 ORM 之一,也是開發時必需學會的技能。這邊主要談的是 Hibernate 與 Spring 的整合部份,關於 Hibernate 映射設定、設定檔配置等則在 Hibernate 相關教學裡說明。
專案結構
project
| pom.xml
|
+---src
+---main
+---java
| \---com
| \---foo
| \---sample
| +---common
| | +---dao
| | | ICategoryRepository.java
| | | IProductRepository.java
| | |
| | \---model
| | Base.java
| | Category.java
| | Product.java
| |
| \-- -hibernate
| \---dao
| | OrmSupport.java
| |
| \---impl
| CategoryRepository.java
| ProductRepository.java
|
\---resources
+---hbm
| category.xml
| product.xml
\---spring
application-hibernate.xml
依賴元件
- Hibernate 撰寫時最新版本為 5.1.0,本次以 3.6.5 為例,
- Spring ORM 撰寫時最新版本為 4.2.6,本次以 3.2.2 為例。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.5.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
Entity 類別
建立要使用及映射的物件。
- Base.java (共用屬性)
package com.foo.sample.common.model;
import java.util.Date;
/**
* Entity 的共用屬性。
* Created by nanashi07 on 2016/5/11.
*/
public class Base {
String createdBy;
Date created;
String modifiedBy;
Date modified;
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(String modifiedBy) {
this.modifiedBy = modifiedBy;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
}
- Category
package com.foo.sample.common.model;
/**
* 分類。
* Created by nanashi07 on 2016/5/11.
*/
public class Category extends Base {
int Id;
String name;
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- Product
package com.foo.sample.common.model;
/**
* 產品。
* Created by nanashi07 on 2016/5/11.
*/
public class Product extends Base {
int id;
String name;
Category category;
String description;
double price;
Double promotion;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Double getPromotion() {
return promotion;
}
public void setPromotion(Double promotion) {
this.promotion = promotion;
}
}
建立物件映射關聯檔 (hbm)
Hibernate 可使用 hbm 檔及 annotation 配置映射關聯性,筆者慣用 hbm 檔,以降低程式碼的耦合性並增加配置的靈活性,可一次配置所有的映射類別,也可各別配置獨立的映射關聯檔,目前採用分別設置映射關聯檔。hbm 檔需放置在 resources 中,以便於整合 Spring 時,能由設定檔(SessionFactoryBean)設定。
- Category 映射關聯性配置(category.xml)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.foo.sample.common.model.Category" table="Category">
<id name="id" column="Id"/>
<property name="name" column="Name"/>
<property name="created" column="Created"/>
<property name="createdBy" column="CreatedBy"/>
<property name="modified" column="Modified"/>
<property name="modifiedBy" column="ModifiedBy"/>
</class>
</hibernate-mapping>
- Product 映射關聯性配置(product.xml)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.foo.sample.common.model.Product" table="Product">
<id name="id" column="Id"/>
<property name="name" column="Name"/>
<one-to-one name="category" class="com.foo.sample.common.model.Category"/>
<property name="description" column="Description"/>
<property name="price" column="Price"/>
<property name="promotion" column="Promotion"/>
<property name="created" column="Created"/>
<property name="createdBy" column="CreatedBy"/>
<property name="modified" column="Modified"/>
<property name="modifiedBy" column="ModifiedBy"/>
</class>
</hibernate-mapping>
撰寫資料存取的 DAO
- 共用的 DAO Support,主要為處理
SessionFactory
的注入。
package com.foo.sample.hibernate.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* {@link HibernateDaoSupport} 處理 {@link SessionFactory} 注入及共用功能。
* Created by nanashi07 on 2016/5/11.
*/
public class OrmSupport extends HibernateDaoSupport {
@Autowired
public void setFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
}
- Category 的存取介面
package com.foo.sample.common.dao;
import com.foo.sample.common.model.Category;
import java.util.List;
/**
* {@link Category} 的存取介面
* Created by nanashi07 on 2016/5/11.
*/
public interface ICategoryRepository {
List<Category> getCategories();
}
- Product 的存取介面
package com.foo.sample.common.dao;
import com.foo.sample.common.model.Product;
import java.util.List;
/**
* {@link Product} 的存取介面
* Created by nanashi07 on 2016/5/11.
*/
public interface IProductRepository {
List<Product> getProducts();
}
- Category DAO 實作
package com.foo.sample.hibernate.dao.impl;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Repository;
import com.foo.sample.common.dao.ICategoryRepository;
import com.foo.sample.common.model.Category;
import com.foo.sample.hibernate.dao.OrmSupport;
/**
* {@link Category} 的存取介面實作。
* Created by nanashi07 on 2016/5/11.
*/
@Repository
public class CategoryRepository extends OrmSupport implements ICategoryRepository {
@Override
public List<Category> getCategories() {
Session session = getSession();
Transaction transaction = session.beginTransaction();
List<Category> values = session.createQuery("from Category").list();
transaction.commit();
return values;
}
}
- Product DAO 實作
package com.foo.sample.hibernate.dao.impl;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Repository;
import com.foo.sample.common.dao.IProductRepository;
import com.foo.sample.common.model.Category;
import com.foo.sample.common.model.Product;
import com.foo.sample.hibernate.dao.OrmSupport;
/**
* {@link Category} 的存取介面實作。
* Created by nanashi07 on 2016/5/11.
*/
@Repository
public class ProductRepository extends OrmSupport implements IProductRepository {
@Override
public List<Product> getProducts() {
Session session = getSession();
Transaction transaction = session.beginTransaction();
List<Product> products = session.createQuery("from Product").list();
transaction.commit();
return products;
}
}
配置 Spring 設定檔
若未與 Spring 整合時,需配置 Hibernate 設定檔 (hibernate.cfg.xml)。與 Spring 整合時則無需此設定檔。此範例版本使用 Hibernate 3.6.5 版本,配合 LocalSessionFactoryBean 或 AnnotationSessionFactoryBean 與 HibernateTransactionManager 使用,若版本不同時,請使用對應的 SessionFactoryBean 與 TransactionManager。
- application-hibernate.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 資料來源/資料庫連接 -->
<bean name="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:sample" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 設置 orm mapping -->
<property name="mappingResources">
<list>
<value>hbm/category.xml</value>
<value>hbm/product.xml</value>
</list>
</property>
<!-- hibernate 相關的設定 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- 交易管理 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>