Hibernate體系架構
Hibernate通過配置文件管理底層的JDBC連接,將用戶從原始的JDBC釋放出來,使得用戶無需再關注底層的JDBC操作,而是以面向對象的方式進行持久化操作。這種全面的解決方案架構如下(插圖來自官方文檔 manual:Comprehensive architecture)
大致解釋一下上面的關鍵分層模塊:
- ==SessionFactory==: 是==單個數據庫映射關==系經過編譯後的內存鏡像,是==線程安全==的。該對象可在進程或者集羣的級別上,爲事務直接可重用數據提供二級緩存。
- ==Session==:是應用程序與持久層交互的一個==單線程==的對象,==所有持久化的對象都必須在Session管理下才可以進行持久化操作==。Session封裝了JDBC,也是Transaction工廠。
- 持久化對象:是一個與Session關聯的普通對象(POJO).
- 瞬態和脫管:未與Sessio==n關聯的POJO處於==瞬態==。如果關聯之後,Session如果關閉了,則此POJO轉爲==脫管狀態。
- ConnectionProvider:是生成JDBC連接的工廠。將應用程序與底層的DataSource及DriverManager隔離開。應用程序一般無需直接訪問這個對象。
- TransactionFactory:生成Transaction對象的工廠。應用程序一般無需直接訪問這個對象。
Hibernate的配置文件
Hibernate持久化操作離不開SessionFactory對象,而SessionFactory對象是由Configuration對象創建的(build)。每一個Hibernate配置文件對應一個Configuration對象,創建Configuration對象的方式有三種:
1.使用hibernate.properties配置文件——這種方式不能在配置文件中直接添加映射文件,而是需要寫到java code裏面,所以比較麻煩:
在Hibernate發佈包的\project\etc下有一個hibernate.properties的用例,比較全面,部分配置如下,
## HypersonicSQL
hibernate.dialect org.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class org.hsqldb.jdbcDriver
hibernate.connection.username sa
hibernate.connection.password
hibernate.connection.url jdbc:hsqldb:./build/db/hsqldb/hibernate
#hibernate.connection.url jdbc:hsqldb:hsql://localhost
#hibernate.connection.url jdbc:hsqldb:test
....
有了這個配置文件還不夠,還需要在java code中寫明映射文件名稱,通過addResource(“xxx.xml”)方式可以添加映射文件,
Configuration cfg = new Configuration()
.addResource("a.hbm.xml")
.addResource("b.hbm.xml");
另外,也可以通過addClass(“xxx.class”)的方式直接添加實體類的Class實例,hibernate會自動搜索對應的映射文件,但是要求將映射文件和實體類放在同一個目錄下。
這種方式有個好處就是消除了系統對文件名的硬編碼耦合。
Configuration cfg = new Configuration()
.addClass(hib.a.class)
.addClass(hib.b.class);
2.使用hibernate.cfg.xml配置文件
即前面的例子,在hibernate.cfg.xml中配置hibernate連接信息,數據池等信息,另外還需要將映射文件名也添加進去,配置如下,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8</property> <!-- 指定字符集的方式-->
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.min_size">1</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<mapping resource="hib/News.hbm.xml" />
</session-factory>
</hibernate-configuration>
配置文件中,需要注意以下幾項配置:
1).編碼:可以在url中指定,例如在hibernate.property中,setProperty(“hibernate.connection.url”,”jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8”)
在hibernate.cfg.xml中, jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8 ,注意在xml文件中&符號要用 &轉義.
2).數據庫方言hibernate.dialect,可以在官方手冊中查找對應的選項
3).自動建表 hibernate.hbm2ddl.auto有三種取值,update, create, create-drop
4).hibernate.show_sql和hibernate.format_sql有助於調試sql,前者可以打印sql到控制檯,後者進行格式化
映射文件News.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hib">
<class name="News" table="news_table">
<id name="id" column="id" type="int">
<generator class="identity" />
</id>
<property name="title" type="string" column="title" />
<property name="content" type="string" column="content" />
</class>
</hibernate-mapping>
3.不使用任何配置文件,所有配置都以編碼方式(.setProperty(key,value))來創建Configuration對象
public static void noConfigFile() {
Configuration cfg = new Configuration()
.addClass(hib.News.class)
.setProperty("hibernate.connection.driver_class","com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url","jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8")
.setProperty("hibernate.connection.username", "root")
.setProperty("hibernate.connection.password", "")
.setProperty("hibernate.c3p0.max_size", "20")
.setProperty("hibernate.c3p0.min_size", "1")
.setProperty("hibernate.c3p0.max_statements", "100")
.setProperty("hibernate.c3p0.timeout", "5000")
.setProperty("hibernate.c3p0.idle_test_period", "3000")
.setProperty("hibernate.c3p0.acquire_increment", "2")
.setProperty("hibernate.validate", "true")
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
.setProperty("hibernate.hbm2dll.auto", "create")
.setProperty("hibernate.show_sql", "true");
SessionFactory sf = cfg.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = sess.beginTransaction();
News n = new News();
n.setTitle("舉頭望明月");
n.setContent("低頭思故鄉");
sess.save(n);
tx.commit();
sess.close();
}