Configuration(AnnotationConfiguration)
作用:進行配置資訊的管理
目標:用來產生SessionFactory
可以在configure方法中指定hibernate設定檔,預設(不指定)時在classpath下載入hibernate.cfg.xml檔案
載入預設的hibernate的設定檔
sessionFactory factory =new AnnotationConfiguration().configure().buildSessionFactory();
載入指定hibernate的設定檔
sessionFactory factory = newnnotationConfiguration().configure("hibernate.xml").buildSessionFactory();
SessionFactory
作用:主要用於產生Session的工廠(資料庫連接池)
當它產生一個Session時,會從資料庫連接池取出一個串連,交給這個Session
Session session= sessionFactory.getCurrentSession();
並且可以通過這個Session取出這個串連
getCurrentSession():表示當前環境沒有Session時,則建立一個,否則不用建立
openSession():表示建立一個Session(3.0以後不常用),使用後需要關閉這個Session
兩方法的區別:
①、openSession永遠是每次都開啟一個新的Session,而getCurrentSession不是,是從上下文找、只有當前沒有Session時,才建立一個新的Session
②、OpenSession需要手動close,getCurrentSession不需要手動close,事務提交自動close
③、getCurrentSession界定事務邊界
所指的上下文是指hibernate設定檔(hibernate.cfg.xml)中的“current_session_context_class”所指的值:(可取值:jta|thread|managed|custom.Class)
<propertyname="current_session_context_class">thread</property>
常用的是:
①、thread:是從上下文找、只有當前沒有Session時,才建立一個新的Session,主要從資料界定事務
②、jta:主要從分布式界定事務,運行時需要Application Server來支援(Tomcat不支援)
③、managed:不常用
④、custom.Class:不常用
Session
save()
session.save(Object)
session的save方法是向資料庫中儲存一個對象,這個方法產生對象的三種狀態
delete()
session.delete(Object)
Object對象需要有ID
對象刪除後,對象狀態為Transistent狀態
load()
格式: Session.load(Classarg0,Serializable arg1) throws HibernateException
arg0:需要載入對象的類,例如:User.class
arg1:查詢條件(實現了序列化介面的對象)。如果是數值類類型,則hibernate會自動使用封裝類,
此方法傳回型別為Object,但返回的是代理對象。
執行此方法時不會立即發出查詢SQL語句。只有在使用對象時,它才發出查詢SQL語句,載入對象。
因為load方法實現了lazy(稱為消極式載入、賴載入)
消極式載入:只有真正使用這個對象的時候,才載入(才發出SQL語句)
hibernate消極式載入實現原理是代理方式。
採用load()方法載入資料,如果資料庫中沒有相應的記錄,則會拋出異常對象不找到(org.hibernate.ObjectNotFoundException)
Get()
格式:Session.get(Classarg0,Serializable arg1)方法
arg0:需要載入對象的類,例如:User.class
arg1:查詢條件(實現了序列化介面的對象):如果是基數類型,則hibernate會自動轉換成封裝類
返回值:此方法傳回型別為Object,也就是對象,再強行轉換為需要載入的對象就可以了。
如果資料不存在,則返回null;
註:執行此方法時立即發出查詢SQL語句。
load()與get()區別
①不存在對應記錄時表現不一樣;
② load返回的是代理對象,等到真正使用對象的內容時才發出sql語句,這樣就要求在第一次使用對象時,要求session處於open狀態,否則出錯
③get直接從資料庫載入,不會消極式載入
get()和load()只根據主鍵查詢,不能根據其它欄位查詢,如果想根據非主鍵查詢,可以使用HQL
update()
①用來更新detached對象,更新完成後轉為為persistent狀態(預設更新全部欄位)
②更新transient對象會報錯(沒有ID)
③更新自己設定ID的transient對象可以(預設更新全部欄位)
④persistent狀態的對象,只要設定欄位不同的值,在session提交時,會自動更新(預設更新全部欄位)
⑤更新部分更新的欄位(更改了哪個欄位就更新哪個欄位的內容)
a)方法1:update/updatable屬性
xml:設定<property>標籤的update屬性,設定在更新時是否參與更新
<property name="name" update="false"/>
注意:update可取值為true(預設):參與更新;false:更新時不參與更新
annotateon:設定@Column的updatable屬性值,true參與更新,false:不參與更新
@Column(updatable=false)
public StringgetTitle(){return title;}
注意:此種方法很少用,因為它不靈活
b)方法2:dynamic-update屬性
注意:此方法目前只適合xml方式,JAP1.0annotation沒有對應的
在實體類的對應檔中的<class>標籤中,使用dynamic-update屬性,true:表示修改了哪個欄位就更新哪個欄位,其它欄位不更新,但要求是同一個session(不能跨session),如果跨了session同樣會更新所有的欄位內容。
<class name="com.bjsxt.Student" dynamic-update="true">
代碼:
@Test public void testUpdate5() { Session session =sessionFactory.getCurrentSession(); session.beginTransaction(); Student s=(Student)session.get(Student.class, 1); s.setName("zhangsan5"); //提交時,會只更新name欄位,因為此時的s為persistent狀態 session.getTransaction().commit(); s.setName("z4"); Session session2 =sessionFactory.getCurrentSession(); session2.beginTransaction(); //更新時,會更新所有的欄位,因為此時的s不是persistent狀態 session2.update(s); session2.getTransaction().commit(); }
如果需要跨session實現更新修改的部分欄位,需要使用session.merget()方法,合并欄位內容
@Test public void testUpdate6() { Session session =sessionFactory.getCurrentSession(); session.beginTransaction(); Student s=(Student)session.get(Student.class, 1); s.setName("zhangsan6"); session.getTransaction().commit(); s.setName("z4"); Session session2 =sessionFactory.getCurrentSession(); session2.beginTransaction(); session2.merge(s); session2.getTransaction().commit();}
這樣雖然可以實現部分欄位更新,但這樣會多出一條select語句,因為在欄位資料合併時,需要比較欄位內容是否已變化,就需要從資料庫中取出這條記錄進行比較
c)使用HQL(EJBQL)物件導向的查詢語言(建議)
@Test public void testUpdate7() { Session session =sessionFactory.getCurrentSession(); session.beginTransaction(); Query q =session.createQuery("updateStudent s sets.name='z5' where s.id = 1"); q.executeUpdate(); session.getTransaction().commit(); }
saveOrUpdate()
在執行的時候hibernate會檢查,如果對象在資料庫中已經有對應的記錄(是指主鍵),則會更新update,否則會添加資料save
clear()
清除session緩衝
無論是load還是get,都會首先尋找緩衝(一級緩衝,也叫session級緩衝),如果沒有,才會去資料庫尋找,調用clear()方法可以強制清除session緩衝
Session session=sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t =(Teacher)session.load(Teacher.class,1); System.out.println(t.getName()); session.clear(); Teacher t2=(Teacher)session.load(Teacher.class, 1); System.out.println(t2.getName()); session.getTransaction().commit();
注意:這樣就會發出兩條SELECT語句,如果把session.clear()去除,則只會發出一條SELECT語句,因為第二次load時,是使用session緩衝中ID為1的對象,而這個對象已經在第一次load到緩衝中了。
flush()
在hibernate中也存在flush這個功能,在預設的情況下session.commit()之前時,其實執行了一個flush命令。
Session.flush功能:
清理緩衝;
執行sql(確定是執行SQL語句(確定產生update、insert、delete語句等),然後執行SQL語句。)
Session在什麼情況下執行flush:
①預設在事務提交時執行;
注意:flush時,可以自己設定,使用session.setFlushMode(FlushMode)來指定。
session.setFlushMode(FlushMode);
FlushMode的枚舉值:
l FlushMode.ALWAYS:任務一條SQL語句,都會flush一次
l FlushMode.AUTO :自動flush(預設)
l FlushMode.COMMIT: 只有在commit時才flush
l FlushMode.MANUAL:手動flush。
l FlushMode.NEVER :永遠不flush 此選項在效能最佳化時可能用,比如session取資料為唯讀時用,這樣就不需要與資料庫同步了
注意:設定flush模式時,需要在session開啟事務之前設定。
②可以顯式的調用flush;
③在執行查詢前,如:iterate.
註:如果主鍵建置原則是uuid等不是由資料庫產生的,則session.save()時並不會發出SQL語句,只有flush時才會發出SQL語句,但如果主鍵建置原則是native由資料庫產生的,則session.save的同時就發出SQL語句。
evict()
例如:session.evict(user)
作用:從session緩衝(EntityEntries屬性)中逐出該對象
但是與commit同時使用,會拋出異常
session =HibernateUtils.getSession();tx =session.beginTransaction(); User1 user = newUser1();user.setName("李四");user.setPassword("123");user.setCreateTime(newDate());user.setExpireTime(newDate()); //利用Hibernate將實體類對象儲存到資料庫中,因為user主鍵建置原則採用的是uuid,所以調用完成save後,只是將user納入session的管理,不會發出insert語句,但是id已經產生,session中的existsInDatabase狀態為falsesession.save(user); session.evict(user);//從session緩衝(EntityEntries屬性)中逐出該對象//無法成功提交,因為hibernate在清理緩衝時,在session的臨時集合(insertions)中取出user對象進行insert操作後需要更新entityEntries屬性中的existsInDatabase為true,而我們採用evict已經將user從session中逐出了,所以找不到相關資料,無法更新,拋出異常。 tx.commit();解決在逐出session緩衝中的對象不拋出異常的方法:在session.evict()之前進行顯示的調用session.flush()方法就可以了。session.save(user); //flush後hibernate會清理緩衝,會將user對象儲存到資料庫中,將session中的insertions中的user對象清除,並且會設定session中的existsInDatabase狀態為falsesession.flush(); session.evict(user);//從session緩衝(EntityEntries屬性)中逐出該對象 //可以成功提交,因為hibernate在清理緩衝時,在Session的insertions中集合中無法找到user對象所以不會發出insert語句,也不會更新session中existsInDatabase的狀態。tx.commit();