# HIBERNATE ## Hibernate基礎概念 Hibernate Session快取機制: 當同樣key值的同樣物件存在,會自動從session裡拿,不會重新到資料庫找 Hibernate中的實體物件可以分為四種狀態:**Transient**、 **Persistent**、**Detached**、**Removed**。 **Transient(暫時)**: 物件剛new出來,沒有結合DB前 **Persistent(永續)**: 與session實例有關聯,且session未關閉前, 1. new出來的Transient物件經過**save()**、**saveOrUpdate()**、**persist()**、**merge()** 方法後 2. 使用**get()**、**load()**、**Query.list()** 等從DB載入拿到物件後 **Detached(分離)**: 當session一關閉,Persistent物件均會變成Detached狀態,所以經過**evict()**、**close()**、**clear()** 等方法後,就會變為Detached狀態, 另外,再次使用**update()**、**saveOrUpdate()**、**merge()** 又可以再將物件變回Persistent **Removed**: 當Persistent物件經過**delete()** 後,由於Persistent物件失去對應的資料,就會變成Removed狀態 ## 第一支Hibernate 1. 加入jar包或Maven引入依賴 2. 建立永續類別,範例 ```java import java.util.*; public class DeptVO implements java.io.Serializable{ private Integer deptno; private String dname; private String loc; public Integer getDeptno() { return deptno; } public void setDeptno(Integer deptno) { this.deptno = deptno; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } } ``` 3. 建立實體映射檔(.hbm.xml),或直接在永續類別加上Annotation ```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.dept.model.DeptVO" table="dept2"> <!-- id name=主鍵的變數名 --> <id name="deptno" column="deptno"> <!-- generator class=主鍵生成規則 --> <generator class="sequence"> <param name="sequence_name">dept2_seq</param> </generator> </id> <!-- 參數名稱name與欄位名稱column的對映 --> <property name="dname" column="dname" /> <property name="loc" column="loc" /> <!-- 由於此為dept對emp的關係,所以為一對多one-to-many --> <!-- cascade為級聯關係,可設定做哪些行為時有級聯,預設為none--> <!-- inverse為主控方關係,預設為false,表示不做控制權反轉,代表一方為主控方 --> <set name="emps" table="emp2" lazy="false" cascade="all" inverse="true" order-by="empno asc"> <!-- 此為emp對應的外鍵 --> <key> <column name="deptno" /> </key> </set> </class> </hibernate-mapping> ``` 4. 建立組態檔(hibernate.cfg.xml) ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 連線池設定 --> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:XE</property> <property name="hibernate.connection.username">user123</property> <property name="hibernate.connection.password">123456</property> <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!-- SQL方言設定,此處使用oracle --> <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property> <!-- 是否要顯示SQL指令 --> <property name="hibernate.show_sql">true</property> <!-- 選擇使用二級快取的供應者,此處選擇NoCacheProvider,可避免快取佔用大量記憶體 --> <property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!--交易管理類型, 以下使用jdbc交易,如果使用被管理的環境如JBoss/WebLogic等就可以使用JTA --> <property name="hibernate.transaction.coordinator_class">jdbc</property> <!-- 使session可以直接取得不用開關 --> <property name="hibernate.current_session_context_class">thread</property> <!-- 告訴Hibernate不是使用預設的單純JDBC連線池 (因目前使用的連線池為c3p0,Hibernate4以後才有此設定)--> <property name="hibernate.temp.use_jdbc_metadata_defaults">false</property> <!-- 此設定可以讓hibernate在啟動時自動生成table --> <!-- create:每次啟動時都自動依照映射檔生成新table create-drop:新建sessionFactory物件時產生新表格,關閉時即刪除 update:新建SessionFactory物件時如表格不存在則產生新的,存在則會比對並更新,此為開發階段最常用的選項 validate:新建SessionFactory物件時只會比對,但不創新的,若表格結構不同會拋出例外 <property name="hbm2ddl.auto">update</property> --> <!-- Java物件與資料庫表格的映射檔 --> <mapping resource="com/dept/model/dept2.hbm.xml" /> </session-factory> </hibernate-configuration> ``` 5. 創建一個方便取用的HibernateUtil類別,可直接拿到SessionFactory 6. 建立一個SessionFactory取得Session即可開始工作 ## 各方法差異: **clear()** vs. **evict()** vs. **flush()** clear() : 清除session內**所有快取** evict(): 只清除**某物件**在session內的快取 flush(): **直接將session內的緩衝區送出**,直接寫入db,但**不會清除**快取,rollback仍會將交易回滾 **update()** vs. **merge()** update(): 清除快取後,如果在快取裡兩個同key值的物件,且傳入的為**Detached物件**,即會拋出例外,更新**失敗** merge(): 清除快取後,即使快取有同樣key值的物件,且傳入Detached物件,**仍然會重新下select指令重新得到Persistent物件**,更新**成功** **get()** vs. **load()** get(): 在呼叫get()後即會**馬上下SQL**到DB拿資料 load(): 使用懶加載,要**實際使用物件裡面的方法時才會到DB**拿資料 **save()** vs. **persist()** save(): 無論**交易範圍內外皆可insert**,**有回傳**值,inert時直接撈回最新的key值並return persist(): **只在交易範圍內**可insert,**無回傳**值,對insert時不會return最新的key值,另外,傳入**detached物件**時,會拋出例外 ## hbm映射配置重點: **one to one** 在class設定: ```java private 類別 變數名; ``` 在hbm檔設定: ```xml <one-to-one name="在自己類別的變數名" class="映射套件+類別名稱" constrained="true" lazy="false"/> ``` Constrained在**one-to-one才可設定**,如果constrained="true",會**延遲加載**,只把主表查出來,如果="false"時,則會一次全部查出來,但在**雙向**關聯中,需設置為**true**,否則會**重複讀取**數據 lazy="false"指定此關聯總是被預先抓取,**不會在需要使用時才到DB裡查**,避免session關閉無法拿到資料 **many to one** 在class設定: ```java private 類別 變數名; ``` 在hbm檔設定: ```xml <many-to-one name="在自己類別的變數名" class="一方映射套件+類別名稱" lazy="false"> <column name="在DB裡用來join的欄位名"/> </many-to-one> ``` **one to many** 在class設定: ```java private Set<類別> 變數名; ``` 在hbm檔設定: ```xml <set name="在自己類別的變數名" table="對應的table" lazy="false" cascade="all"> <key> <column name="在DB裡用來join的欄位名" /> </key> <one-to-many class="多方映射套件+類別名稱" /> </set> ``` ## 實作DAO重點: -無論何種查詢都需先配置好映射! **原生SQL查詢** ```java SQLQuery q = session.createSQLQuery("SQL where 欄位=:參數名"); q.setParameter("參數名",帶入值); query.addEntity(型別.class); //注意沒有加上此行會出現ClassCastException q.list(); //拿到list,配置好也可直接泛型拿到原本物件(注意:需對應到class裡面設定的順序,對到物件型別時,SQL則用id去mapping) //Join外鍵直接寫在SQL語句 ``` **HQL查詢** ```java Query q = session.createQuery("select a from Aclass a join a.在Aclass的變數名"); q.setParameter("參數名",帶入值); q.list(); //拿到list,再直接用泛型接 ``` **Criteria查詢** ```java Criteria criteria = session.createCriteria(Aclass.class); criteria.createAlias("原本在Aclass 裡的變數名","更改的別名,也可直接用一樣"); criteria.add(); //加限制條件 criteria.list(); //拿到list,直接用泛型接 ``` -注意: table如果尚未commit是無法拿到資料的! -注意: SQLQuery與Query需分清楚!
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up