Hibernate原理與應用
主要內容
1、引入
2、安裝配置
3、基本概念和CURD
4、HQL和Criteria
5、關聯映射
6、繼承映射
7、集合映射
8、懶加載
9、緩存
10、事務
11、其他
12、Hibernate不適合的場景
13、與JPA的集成(annotation方式)
14、最佳實踐
1、引入
模型不匹配(阻抗不匹配)
?????? Java面向對象語言,對象模型,其主要概念有:繼承、關聯、多態等;數據庫是關系模型,其主要概念有:表、主鍵、外鍵等。
解決辦法
?????? 1使用JDBC手工轉換。
?????? 2使用ORM(Object Relation Mapping對象關系映射)框架來解決,主流的ORM框架有Hibernate、TopLink、OJB。
安裝配置
下載地址http://www.hibernate.org
將下載目錄/hibernate3.jar和/lib下的hibernate運行時必須的包加入classpath中:
?????? antlr.jar,cglib.jar,asm.jar,commons-collections.jar,commons-logging.jar,jta.jar,dom4j.jar
?
配置文件hibernate.cfg.xml和hibernate.properties,XML和properties兩種,這兩個文件的作用一樣,提供一個即可,推薦XML格式,下載目錄/etc下是示例配置文件。
?????? 可以在配置文件指定:
?????? 數據庫的URL、用戶名、密碼、JDBC驅動類、方言等。
?????? 啟動時Hibernate會在CLASSPATH里找這個配置文件。
映射文件(hbm.xml,對象模型和關系模型的映射)。在/eg目錄下有完整的hibernate示例。
快速開始小例子
基本概念和CURD
開發流程
?????? 1由Domain object -> mapping->db。(官方推薦)
?????? 2由DB開始,用工具生成mapping和Domain object。(使用較多)
?????? 3由映射文件開始。
基本概念和CURD
Domain Object限制
?????? 1.默認的構造方法(必須的)。
?????? 2有無意義的標示符id(主鍵)(可選)
?????? 3非final的,對懶加載有影響(可選)
?????? Domain Java Object(User)
public class User {
?????? private int id;
?????? private String name;
?????? private Date birthDay;
?
?????? //getter setter…
}
?
1.hbm.xml
<?xml version="1.0"?>
<hibernate-mapping package=“cn.itcast.domain">
<class name="User" table="user">
?????? <id name="id">
????????????? <generator class="native"/>
?????? </id>
?????? <property name="name"/>
?????? <property name="birthday”/>
</class>
</hibernate-mapping>
?
Java代碼
?????? 1.初始化代碼(只做一次)
?????? ?Configuration cfg = new Configuration();
?????? ?cfg.configure(“config.cfg.xml”);
?????? ?也可以通過cfg.setProperty設置屬性。
?????? ?SessionFactory sessionFactory = cfg.buildSessionFactory();???
?????? 2.模板代碼
Session session = null;Transaction tx = null;
try{
?????? session = sessionFactory.openSession();
?????? tx = session.beginTransaction();
?????? //…你的代碼save,delete,update,get…
?????? tx.commit();
}catch(Exception e){
?????? if(tx !=null)tx.rollback();throw e;
}finally{
?????? if(session != null)session.close();
}
?
Session的幾個主要方法
?????? 1.save,persist保存數據,persist在事務外不會產生insert語句。
?????? 2.delete,刪除對象
?????? 3.update,更新對象,如果數據庫中沒有記錄,會出現異常。
?????? 4.get,根據ID查,會立刻訪問數據庫。
?????? 5.Load,根據ID查,(返回的是代理,不會立即訪問數據庫)。
?????? 6.saveOrUpdate,merge(根據ID和version的值來確定是save或update),調用merge你的對象還是托管的。
?????? 7.lock(把對象變成持久對象,但不會同步對象的狀態)。
對象狀態
瞬時(transient):數據庫中沒有數據與之對應,超過作用域會被JVM垃圾回收器回收,一般是new出來且與session沒有關聯的對象。
持久(persistent):數據庫中有數據與之對應,當前與session有關聯,并且相關聯的session沒有關閉,事務沒有提交;持久對象狀態發生改變,在事務提交時會影響到數據庫(hibernate能檢測到)。
脫管(detached):數據庫中有數據與之對應,但當前沒有session與之關聯;托管對象狀態發生改變,hibernate不能檢測到。
?
HQL和Criteria
HQL(Hibernate Query Language)
?????? 面向對象的查詢語言,與SQL不同,HQL中的對象名是區分大小寫的(除了JAVA類和屬性其他部分不區分大小寫);HQL中查的是對象而不是和表,并且支持多態;HQL主要通過Query來操作,Query的創建方式:
?????? Query q = session.createQuery(hql);
from Person
from User user where user.name=:name
from User user where user.name=:name and user.birthday < :birthday
Criteria
?????? Criteria是一種比HQL更面向對象的查詢方式;Criteria的創建方式:
?????? Criteria crit = session.createCriteria(DomainClass.class);
?????? 簡單屬性條件如:criteria.add(Restrictions.eq(propertyName, value)),
?????? criteria.add(Restrictions.eqProperty(propertyName,otherPropertyName))
?
基本功能練習
實現UserDao
?????? public interface UserDao {
?????? public void saveUser(User user);
?????? public User findUserById(int id);
?????? public User findUserByName(String name);
?????? public void updateUser(User user);
?????? public void remove(User user);
?????? }
?
實驗步驟:
1.設計domain對象User。
2.設計UserDao接口。
3.加入hibernate.jar和其依賴的包。
4.編寫User.hbm.xml映射文件,可以基于hibernate/eg目錄下的org/hibernate/auction/User.hbm.xml修改。
5.編寫hibernate.cfg.xml配置文件,可以基于hibernate/etc/hibernate.cfg.xml修改;必須提供的幾個參數:
?????? connection.driver_class、connection.url、connection.username、connection.password、dialect、hbm2ddl.auto。
6.編寫HibernateUtils類,主要用來完成Hibnerate初始化和提供一個獲得Session的方法;這步可選。
7.實現UserDao接口。
關聯映射
多對一(Employee - Department)
一對多(Department-Employee)
一對一(room - door)
多對多(teacher - student)
組件映射(User-Name)
集合映射(set, list, map, bag)
inverse和cascade(Employee– Department)
?
多對一(Employee - Department)
映射文件<many-to-one name=”depart” column=”depart_id”/>
ER圖
?
關聯映射
一對多(Department-Employee)
<set name=”employees”>
????????????? <key column=”depart_id”/>
????????????? <one-to-many class=”Employee”/>
</set>
?
一對一(Person - IdCard)
1)基于主鍵的one-to-one(person的映射文件)
<id name=”id”>
?????? <generator class=”foreign”><param name=”property”>idCard</param></generator>
<id>
<one-to-one name=”idCard” constrained=”true”/>
一對一(Person - IdCard)
2)基于外健的one-to-one,可以描述為多對一,加unique=“true”約束
<one-to-one name=”idCard” property-ref=“person”/>
???????????? property-ref用于指定關聯類的一個屬性,這個屬性將會和本外鍵相對應
<many-to-one name=”person” column=”person_id” unique=”true” not-null=”true”/>
?<!-唯一的多對一,其實就便成了一對一了-->
關聯映射
多對多(teacher - student)
在操作和性能方面都不太理想,所以多對多的映射使用較少,實際使用中最好轉換成一對多的對象模型;Hibernate會為我們創建中間關聯表,轉換成兩個一對多。
<set name="teacher" table="teacher_student">
????????????? <key column="teacher_id"/>
????????????? <many-to-many class="Student" column="student_id"/>
</set>
關聯映射
組件映射(User-Name)
關聯的屬性是個復雜類型的持久化類,但不是實體即:數據庫中沒有表與該屬性對應,但該類的屬性要之久保存的。
<component name=”name” class=”com.test.hibernate.domain.Name”>
????????????? <property name=”initial”/>
????????????? <property name=”first”/>
????????????? <property name=”last”/>
</component>
當組件的屬性不能和表中的字段簡單對應的時候可以選擇實現:
org.hibernate.usertype. UserType或
org.hibernate.usertype. CompositeUserType
對于一些不是復雜的實體類我們可以在數據庫中沒有表與之相對應
這時可選用Component組件
繼承映射
對象模型(Java類結構)
?
繼承映射
一個類繼承體系一張表(subclass)(表結構)
繼承映射
一個類繼承體系一張表(subclass)(映射文件)
<class name="Employee" table="employee" discriminator-value="0">
????????????? <id name="id">
???????????????????? <generator class="native"/>
????????????? </id>
????????????? <discriminator column="type" type="int"/>
????????????? <property name="name"/>
????????????? <many-to-one name=”depart” column=”depart_id”/>
????????????? <subclass name="Skiller" discriminator-value="1">
???????????????????? <property name=”skill”/>
????????????? </subclass>
????????????? <subclass name="Sales" discriminator-value="2">
???????????????????? <property name="sell"/>
????????????? </subclass>
</class>
一張表映射出一個繼承樹?操作就是一張表查詢的效率高
缺點:對于新增加某一個類型時就要修改表結構信息且有的字段必須可以為NULL
繼承映射
每個子類一張表(joined-subclass) (表結構)
多態查詢效率會很低要將所有的表來查詢一遍
每個子類都存儲為一張表
這是當每個子類的屬性差別都很大時會用該種方式來處理
繼承映射
每個子類一張表(joined-subclass) (映射文件)
<class name="Employee" table="employee">
????????????? <id name="id">
???????????????????? <generator class="native"/>
????????????? </id>
????????????? <property name="name"/>
????????????? <joined-subclass name="Skiller" table="skiller">
???????????????????? <key column="employee_id"/>
???????????????????? <property name="skill"/>
</joined-subclass>
<joined-subclass name="Sales" table="sales">
?????? <key column="employee_id"/>
?????? <property name="sell"/>
</joined-subclass>
</class>
繼承映射
混合使用“一個類繼承體系一張表”和“每個子類一張表” (表結構)
繼承映射
混合使用“一個類繼承體系一張表”和“每個子類一張表” (映射文件)
<class name="Employee" table="employee">
????????????? <id name="id">
???????????????????? <generator class="native"/>
????????????? </id>
????????????? <discriminator column="type"/>
????????????? <property name="name"/>
????????????? <subclass name="Skiller">
???????????????????? <property name="net"/>
????????????? </subclass>
????????????? <subclass name=”Sales”">
???????????????????? <join table="sales">
??????????????????????????? <key column="employee_id"/>
??????????????????????????? <property name="sell"/>
???????????????????? </join>
????????????? </subclass>
</class>
繼承映射
每個具體類一張表(union-subclass) (表結構)
根據主鍵來查詢
要求三張表的id都是不同的如果用這種結構來實現()
增刪改都是直接對單表進行操作
進行查詢時有可能對三張表來進行查詢(但hibernate會進行子查詢連接查詢)
繼承映射
每個具體類一張表(union-subclass) (映射文件)
<class name="Employee" abstract="true">
????????????? <id name="id">
???????????????????? <generator class="hilo"/>
????????????? </id>
????????????? <property name="name"/>
????????????? <union-subclass name="Skiller" table="skiller">
???????????????????? <property name="skill"/>
????????????? </union-subclass>
????????????? <union-subclass name="Sales" table="sales">
???????????????????? <property name="sell"/>
????????????? </union-subclass>????????
?????? </class>
主健不能是identity類型,如果父類是abstract=”true”就不會有表與之對應。
隱式多態,映射文件沒有聯系,限制比較多很少使用。
集合映射
集合映射(set, list, array,bag, map)
<set name=”employees” >
????????????? <key column=”depart_id”/>
????????????? <one-to-many class=”Employee”/>
????????????? <!-- <element type="string" column="name"/> -->
????????????? <!--
???????????????????? <composite-element class=”YourClass”>
??????????????????????????? <property name=”prop1”/>
??????????????????????????? <property name=”prop2”/>
???????????????????? </composite>
????????????? -->
</set>
?
集合映射(set, list, array,bag, map)
<list name=”employees” >
????????????? <key column=”depart_id”/>
????????????? <!—表中有單獨的整型列表示list-index ?
????????????? <list-index column=”order_column”/>
????????????? <one-to-many class=”Employee”/>
</list>
<array name=”employees” >
????????????? <key column=”depart_id”/>
????????????? <!—表中有單獨的整型列表示list-index ?
????????????? <list-index column=”order_column”/>
????????????? <one-to-many class=”Employee”/>
</array>
?
集合映射(set, list, array,bag, map)
<bag name="employees " order-by="id desc">
????????????? <key column=”depart_id”/>????????????????
????????????? <one-to-many class=”Employee”/>
</bag>
<map name="employees ">
????????????? <key column=”depart_id”/>
????????????? <map-key type="string" column="name"/>
????????????? <one-to-many class=”Employee”/>
</map>
?
集合映射(set, list, array,bag, map)
這些集合類都是Hibernate實現的類和JAVA中的集合類不完全一樣,set,list,map分別和JAVA中的Set,List,Map接口對應,bag映射成JAVA的List;這些集合的使用和JAVA集合中對應的接口基本一致;在JAVA的實體類中集合只能定義成接口不能定義成具體類,因為集合會在運行時被替換成Hibernate的實現。
集合的簡單使用原則:大部分情況下用set,需要保證集合中的順序用list,想用java.util.List又不需要保證順序用bag。
集合映射
cascade和inverse (Employee– Department)
Casade用來說明當對主對象進行某種操作時是否對其關聯的從對象也作類似的操作,常用的cascade:
?????? none,all,save-update ,delete, lock,refresh,evict,replicate,persist,
?????? merge,delete-orphan(one-to-many)。一般對many-to-one,many-to-many不設置級聯,在<one-to-one>和<one-to-many>中設置級聯。
inverse表“是否放棄維護關聯關系”(在Java里兩個對象產生關聯時,對數據庫表的影響),在one-to-many和many-to-many的集合定義中使用,inverse=”true”表示該對象不維護關聯關系;該屬性的值一般在使用有序集合時設置成false(注意hibernate的缺省值是false)。
?????? one-to-many維護關聯關系就是更新外鍵。many-to-many維護關聯關系就是在中間表增減記錄。
?????? 注:配置成one-to-one的對象不維護關聯關系
?
懶加載
通過asm和cglib二個包實現;Domain是非final的。
1.session.load懶加載。
2.one-to-one(元素)懶加載:
?????? 必需同時滿足下面三個條件時才能實現懶加載
?????? (主表不能有constrained=true,所以主表沒有懶加載)
?????? lazy!=false 2)constrained=true 3)fetch=select
3.one-to-many (元素)懶加載:1)lazy!=false 2)fetch=select
4.many-to-one (元素):1)lazy!=false 2)fetch=select
5.many-to-many (元素):1)lazy!=false 2)fetch=select
6.能夠懶加載的對象都是被改寫過的代理對象,當相關聯的session沒有關閉時,訪問這些懶加載對象(代理對象)的屬性(getId和getClass除外)hibernate會初始化這些代理,或用Hibernate.initialize(proxy)來初始化代理對象;當相關聯的session關閉后,再訪問懶加載的對象將出現異常。
初始時就創建了一個對象
如果你不需要那么它就不會去訪問數據庫
只有要真正需要數據時則需在session未關閉時去訪問下數據庫
對于一對一的情況下?主表的查詢沒有懶加載會從數據庫中將從表查詢出來?????????????????? ???從表默認是不會加載而是返回代理形式會有懶加載的形式
對于一對多缺省是懶加載的如果不是就會當我們例如查詢部門時會將所有的員工信息都查出來
對于getID()??和 getClass() 這都是不需要訪問數據庫的?不會初始化代理對象
對于相應映射關系時存在懶加載的機制
緩存
緩存的作用主要用來提高性能,可以簡單的理解成一個Map;使用緩存涉及到三個操作:把數據放入緩存、從緩存中獲取數據、刪除緩存中的無效數據。
一級緩存,Session級共享。
?????? save,update,saveOrUpdate,load,get,list,iterate,lock這些方法都會將對象放在一級緩存中,一級緩存不能控制緩存的數量,所以要注意大批量操作數據時可能造成內存溢出;可以用evict,clear方法清除緩存中的內容。
緩存
二級緩存,SessionFactory級共享。
實現為可插拔,通過修改cache.provider_class參數來改變;
?????? hibernate內置了對EhCache,OSCache,TreeCache,SwarmCache的支持,可以通過實現CacheProvider和Cache接口來加入Hibernate不支持的緩存實現。
在hibernate.cfg.xml中加入:
?????? <class-cache class="className" usage="read-only"/>
?????? 或在映射文件的class元素加入子元素:
?????? <cache usage="read-write"/>
?????? 其中usage:read-only,read-write,nonstrict-read-write,transactional
Session的:save(這個方法不適合native生成方式的主鍵),
?????? update,saveOrUpdate,list,iterator,get,load,以及Query,Criteria都會填充二級緩存,但只有(沒打開查詢緩存時)Session的iterator,get,load會從二級緩存中取數據(iterator可能存在N+1次查詢)。
Query,Criteria(查詢緩存)由于命中率較低,所以hibernate缺省是關閉;修改cache.use_query_cache為true打開對查詢的緩存,并且調用query.setCacheable(true)或criteria.setCacheable(true)。
SessionFactory中提供了evictXXX()方法用來清除緩存中的內容。
統計信息打開generate_statistics,用sessionFactory.getSatistics()獲取統計信息。
緩存
分布式緩存和中央緩存。
使用緩存的條件
1.讀取大于修改。
2.數據量不能超過內存容量。
3.對數據要有獨享的控制。
4.可以容忍出現無效數據。
事務
JDBCTransaction
?????? 單個數據庫(一個SesisonFactory對應一個數據庫),由JDBC實現。
?????? Session session = null;
?????? Transaction tx =null;
?????? try {
????????????? session = sessionFactory.openSession();
????????????? tx = session.beginTransaction();
????????????? //process
????????????? tx.commit();
?????? } catch(HibernateException e){
????????????? if(tx != null)tx.rollback();throw e;
?????? }finally {
????????????? if (session != null)session.close();
?????? }
?????? connection.setAutoCommit(false);
?????? connection.commit();conn.rollback();
?
JTATransaction
?????? 可以簡單的理解成跨數據庫的事物,由應用JTA容器實現;使用JTATransaction需要配置hibernate.transaction.factory_class參數,該參數缺省值是org.hibernate.transaction. JDBCTransactionFactory,當使用JTATransaction時需要將該參數改成org.hibernate.transaction.JTATransactionFactory,并配置jta.UserTransaction參數JNDI名(Hibernate在啟動JTATransaction時要用該值到JNDI的上下文Context中去找javax.transaction.UserTransaction)。
javax.transaction.UserTransactin tx = context.lookup(“jndiName”);
try{
?????? tx.begin();
?????? //多個數據庫的session操作;
?????? //session1….
?????? //session2….
?????? tx.commit();
}catch(Exception e){
?????? tx.rollback(); throw e;
}
?
session context和事務邊界
?????? 用current_session_context_class屬性來定義context(用sessionFactory.getCurrentSession()來獲得session),其值為:
1.thread:ThreadLocal來管理Session實現多個操作共享一個Session,避免反復獲取Session,并控制事務邊界,此時session不能調用close當commit或rollback的時候session會自動關閉(connection.release_mode:after_transaction)。
????????????? Open session in view:在生成(渲染)頁面時保持? session打開。
2.jta:由JTA事務管理器來管理事務(connection.release_mode:after_statement)。
悲觀鎖和樂觀鎖
?????? 悲觀鎖由數據庫來實現;樂觀鎖hibernate用version和timestamp來實現
事務邊界 開啟提交 回滾
如想在業務邏輯層控制事務??但業務邏輯層不會與數據訪問層有相當大的耦合
Transaction因為是業務邏輯層的對象
悲觀鎖我讀取到信息時會對信息進行加鎖操作等數據修改完后對數據鎖進行釋放其他才能修改(不可取)
看數據庫的版本號與提交的版本號哪個更加新如果數據庫的新則不允許提交的
其他問題
hibernate.cfg.xml和hbm.xml內容解釋
數據類型
?????? ?1.<property name=“name” type=“java.lang.String”/>
?????? ? type可以是hibernate、java類型或者你自己的類型(需要實現hibernate的一個接口)。
?????? 2.基本類型一般不需要在映射文件(hbm.xml)中說明,只有在一個JAVA類型和多個數據庫數據類型相對應時并且你想要的和hibernate缺省映射不一致時,需要在映射文件中指明類型(如:java.util.Date,數據庫DATE,TIME,DATATIME,TIMESTAMP,hibernate缺省會把java.util.Date映射成DATATIME型,而如果你想映射成TIME,則你必須在映射文件中指定類型)。
?????? 3.數據類型的對應關系見參考文檔5.2.2
Session是非線程安全的,生命周期較短,代表一個和數據庫的連接,在B/S系統中一般不會超過一個請求;內部維護一級緩存和數據庫連接,如果session長時間打開,會長時間占用內存和數據庫連接。
SessionFactory是線程安全的,一個數據庫對應一個SessionFactory,生命周期長,一般在整個系統生命周期內有效;SessionFactory保存著和數據庫連接的相關信息(user,password,url)和映射信息,以及Hibernate運行時要用到的一些信息。
session內部封裝了connection連接
對于session盡量晚的獲得盡量早的釋放
?
對于主鍵為自動增長類型因為要從數據庫中獲取才能進行插入所以會直接進入數據庫
而不像其他類型先進入緩存等提交時才與數據庫交互
其他問題
flush時將一級緩存與數據庫同步
大批處理
?????? 大量操作數據時可能造成內存溢出,解決辦法如下:
?????? 1.清除session中的數據
?????? for(int i=0;i<100000;i++)session.save(obj);
?????? for(int i=0;i<100000;i++){
????????????? session.save(obj);
????????????? if(i% 50 == 0){session.flush();???? session.clear();}
?????? }
?????? 2.用StatelessSession接口:它不和一級緩存、二級緩存交互,也不觸發任何事件、監聽器、攔截器,通過該接口的操作會立刻發送給數據庫,與JDBC的功能一樣。
?????? StatelessSession s = sessionFactory.openStatelessSession();該接口的方法與Session類似。
?????? 3.Query.executeUpdate()執行批量更新,會清除相關聯的類二級緩存(sessionFactory.evict(class)),也可能會造成級聯,和樂觀鎖定出現問題
?
其他問題
HQL
?????? 1查詢多個對象select art, user from Article art, User user where art.author.id=user.id and art.id=:id這種方式返回的是Object[],Object[0]:article,Object[1]:user。
?????? 2分頁query.setFirstResult,query.setMaxResults.
?????? ? 查詢記錄總數query.iterate(“select count(*) from Person”).next()
?????? 3批量更新query.executeUpdate()可能造成二級緩存有實效數據。
Criteria
?????? 1排序Criteria.addOrder(Order.desc(propertyName));
?????? 2關聯查詢criteria.setFetchMode(“propertyName”, FetchMode.SELECT)與映射文件中關聯關系的fetch作用一致。
?????? 3投影Projections.rowCount(),max(propertyName), avg, groupProperty…
?????? 4分頁Projections.rowCount(),criteria.setFirstResult(),criteria.setMaxResults()
?????? 5DetachedCriteria可在session外創建(在其他層創建比如在Service中創建)然后用getExecutableCriteria(session)方法創建Criteria對象來完成查詢。
?????? 6Example查詢,Example.create(obj);criteria.add(example)。
查詢表達式是不會利用緩存來進行查詢的(默認情況下)
離線查詢實現動態查詢DetachedCriteria?他構造時不需要session
而Cruteria構造時需要
其他問題
N+1次查詢和懶加載
?????? 1.用Query.iterator可能會有N+1次查詢。
?????? 2.懶加載時獲取關聯對象。
?????? 3.如果打開對查詢的緩存即使用list也可能有N+1次查詢。
攔截器與事件
?????? 攔截器與事件都是hibernate的擴展機制,Interceptor接口是老的實現機制,現在改成事件監聽機制;他們都是hibernate的回調接口,hibernate在save,delete,update…等會回調這些類。
SQL和命名查詢
用Map代替Domain對象;將對象轉化為XML。
?
命名查詢是將查詢語句集中起來到配置文件中更方便的修改
Hibernate不適合的場景
不適合OLAP(On-Line Analytical Processing聯機分析處理),以查詢分析數據為主的系統;適合OLTP(on-line transaction processing聯機事務處理)。
對于些關系模型設計不合理的老系統,也不能發揮hibernate優勢。
數據量巨大,性能要求苛刻的系統,hibernate也很難達到要求,批量操作數據的效率也不高。
與JPA的集成(annotation方式)
需要添加的包ejb3-persistence.jar, hibernate-entitymanager.jar, hibernate-annotations.jar, hibernate-commons-annotations.jar, jboss-archive-browsing.jar, javassist.jar
?配置文件%CLASSPATH%/META-INF/persistence.xml
JAVA代碼:
?????? EntityManagerFactory emf = Persistence.createEntityManagerFactory(name);
?????? //(Name:在persistence.xml中指定。)
?????? EntityManager em = emf.createEntityManager();
?????? EntityTransaction tx = em.getTransaction();
?????? Tx.begin();
?????? Em.persist(entity);//remove,merge,find
?????? Tx.commit();
?????? Em.close();
?????? Emf.close();
最佳實踐
見hibernate參考文檔
?
?