Hibernate4.x之Session--常用方法


接上篇文章繼續學習Hibernate的Session(http://www.cnblogs.com/dreamfree/p/4111777.html)

持久化對象的狀態;
  站在持久化的角度,Hibernate把對象分為4種狀態:持久化狀態、臨時狀態、游離狀態、刪除狀態。
  Session的特定方法能使對象從一個狀態轉換到另一個狀態。

  臨時對象(Transient):
    在使用代理主鍵的情況下,OID通常為null
    不處於Session的緩存中
    在數據庫中沒有對應的記錄
  持久化對象(也叫“托管”)(Persist)
    OID為null
    位於Session緩存中
    若在數據庫中已經有和其對應的記錄,持久化對象和數據庫中的相關記錄對應
    Session在flush緩存時,會根據持久化對象的屬性變化,來同步更新數據庫
    在同一個Session實例的緩存中,數據庫表中的每條記錄只對應唯一的持久化對象
  刪除對象(Removed):
    在數據庫中沒有和其OID對應的記錄
    不再處於Session緩存中
    一般情況下,應用程序不該再使用被刪除的對象
  游離對象(也叫"脫管")(Detached):
    OID不為null
    不再處於Session緩存中
    一般情況下,游離對象是由持久化對象轉變過來的,因此在數據庫中可能還存在與它對應的記錄

下面的圖片說明了Hibernate中對象狀態的轉換:


Session的save方法
  Session的save()方法使一個臨時對象轉變為持久化對象
  Session的save()方法完成以下操作:
    把News對象加入到Session緩存中,使它進入持久化狀態
    選用映射文件指定的標識符生成器,為持久化對象分配唯一的OID,在使用代理主鍵的情況下,setId()方法為News對象設置OID是無效的
    計划執行一條insert語句:在flush緩存的時候
  Hibernate通過持久化對象的OID來維持它和數據庫相關記錄的對應關系。當News對象處於持久化狀態時,不允許程序隨意修改它的ID


  persist()和save()的區別:
    當對一個OID不為null的對象執行save()方法時,會把該對象以一個新的OID保存到數據庫中;但執行persist()方法時會拋出一個異常

Session的get()和load()方法
  都可以根據給定的OID從數據庫加載一個持久化對象
區別:
  當數據庫中不存在與OID對應的記錄時,load()方法拋出ObjectNotFoundException異常,而get()方法返回null
  兩者采用不同的延遲檢索策略:load()方法支持延遲加載策略。而get不支持

Session的update()方法
  Session的update()方法使一個游離對象轉變為持久化對象,並且計划執行一條update語句
  若希望Session僅當修改了News對象的屬性時,才執行update()語句,可以把映射文件中<class>元素的select-before-update設為true。該屬性的默認值為false
  當update()方法關聯一個游離對象時,如果在Session的緩存中已經存在相同的OID的持久化對象,會拋出異常
  當update()方法關聯一個游離對象時,如果數據庫中不存在相應的記錄,也會拋出異常

Session的saveOrUpdate()方法
  Session的saveOrUpdate()方法同時包含了save()與update()方法的功能

  

  


判定對象為臨時對象的標准
  Java對象的OID為null
  映射文件中的<id>設置了unsaved-value屬性,並且Java對象的OID取值與這個unsaved-value屬性值匹配

Session的merge()方法

  

  


Session的delete()方法
  Session的delete()方法既可以刪除一個游離對象,也可以刪除一個持久化對象
  Session的delete()方法處理過程
  計划執行一條delete語句
  把對象從Session的緩存中刪除,該對象進入刪除狀態
  Hibernate的cfg.xml配置文件中有一個hibernate.use_identifier_rollback屬性,其默認值為false,若把它設為true,將改變delete()方法的運行行為:delete()方法會把持久化對象或游離對象的OID設置為null,使它們變為臨時對象

通過Hibernate調用存儲過程
  work接口:直接通過JDBC API來訪問數據庫的操作

  Session的doWork(Work)方法用於執行Work對象指定的操作,即調用Work對象的execute()方法。Session會把當前使用的數據庫連接傳遞給execute()方法

Hibernate與觸發器協同工作
  Hibernate與數據庫中的觸發器協同工作時,會造成兩類問題
    觸發器使Session的緩存中的持久化對象與數據庫中對應的數據不一致;觸發器運行在數據庫中,它執行的操作對Session是透明的
    session的update()方法盲目地激發觸發器;無論游離對象的屬性是否發生變化,都會執行update語句,而update語句會激發數據庫中相應的觸發器
解決方案:
  在執行完Session的相關操作后,立即調用Session的flush()方法和refresh()方法,迫使Session的緩存與數據庫同步(refresh()方法重新從數據庫加載對象)

  在映射文件的<class>元素中設置select-before-update屬性;當Session的update或saveOrUpdate()方法更新一個游離對象時,會先執行select語句,獲得當前游離對象在數據庫中的最新數據。只有在一致的情況下才會執行update語句

 

測試類:

  1 package com.yl.hibernate.entities;
  2 
  3 import static org.junit.Assert.*;
  4 
  5 import java.sql.CallableStatement;
  6 import java.sql.Connection;
  7 import java.sql.SQLException;
  8 import java.util.Date;
  9 
 10 import org.hibernate.Session;
 11 import org.hibernate.SessionFactory;
 12 import org.hibernate.Transaction;
 13 import org.hibernate.cfg.Configuration;
 14 import org.hibernate.jdbc.Work;
 15 import org.hibernate.service.ServiceRegistry;
 16 import org.hibernate.service.ServiceRegistryBuilder;
 17 import org.junit.After;
 18 import org.junit.Before;
 19 import org.junit.Test;
 20 
 21 public class HibernateTest {
 22 
 23     private SessionFactory sessionFactory;
 24     private Session session;
 25     private Transaction transaction;
 26     
 27     @Before
 28     public void init() {
 29         Configuration configuration = new Configuration().configure();
 30         ServiceRegistry serviceRegistry = 
 31                 new ServiceRegistryBuilder().applySettings(configuration.getProperties())
 32                                             .buildServiceRegistry();
 33 
 34         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 35         
 36         session = sessionFactory.openSession();
 37 
 38         transaction = session.beginTransaction();
 39     }
 40     @After
 41     public void destory() {
 42         transaction.commit();
 43         
 44         session.close();
 45         
 46         sessionFactory.close();
 47     }
 48     
 49     @Test
 50     public void testSessionCache() {
 51         News news = (News)session.get(News.class, 21);
 52         System.out.println(news);
 53         session.flush();
 54         News news2 = (News)session.get(News.class, 21);
 55         System.out.println(news2);
 56         
 57         System.out.println(news == news2);//true
 58     }
 59 
 60     /**
 61      * flush:使數據庫表中的記錄和Session緩存中的對象的狀態保持一致。為了保持一致,則可能會發送對應的SQL語句。
 62      *     1.在Transaction的commit()方法中:先調用session的flush方法,再提交事務
 63      *  2.flush()方法可能會發送SQL語句,但不會提交事務
 64      *  3.注意:在為提交事務或顯示調用session.flush()方法 之前,也有可能會flush()操作。
 65      *      1).執行HQL或QBC查詢,會先進行flush操作,以得到數據表的最新紀錄
 66      *      2).若記錄的ID是由底層數據庫使用自增的方式生成的,則在調用save方法時,就會立即發送INSERT語句
 67      *  因為save方法后,必須保證對象的ID是存在的!
 68      */
 69     @Test
 70     public void testFlush2() {
 71         News news = new News("Hibernate", "oracle", new Date());
 72         session.save(news);
 73     }
 74     
 75     @Test
 76     public void testFlush() {
 77         /*News news = (News)session.get(News.class, 21);
 78         news.setAuthor("Bruce Eckel");
 79         
 80         News news2 = (News)session.createCriteria(News.class).uniqueResult();
 81         System.out.println(news2);*/
 82         News news = (News)session.get(News.class, 22);
 83         session.flush();
 84         System.out.println(news);
 85     }
 86     
 87     /**
 88      * refresh():會強制發送SELECT 語句,以使Session緩存中對象的狀態和數據表中對應的記錄保持一致!
 89      */
 90     @Test
 91     public void testRefresh() {
 92         News news = (News) session.get(News.class, 22);
 93         System.out.println(news);
 94         session.refresh(news);
 95         System.out.println(news);
 96     }
 97     
 98     /**
 99      * clear():清理緩存
100      */
101     @Test
102     public void testClear() {
103         News news1 = (News) session.get(News.class, 21);
104         session.clear();
105         News news2 = (News) session.get(News.class, 21);
106     }
107     
108     /**
109      * save()方法:
110      *     1.使一個臨時對象變為持久化對象
111      *     2.為對象分配ID
112      *     3.在flush緩存時會發送一條insert語句
113      *     4.在save方法之前的id是無效的
114      *     5.持久化對象的ID是不能被修改的!
115      */
116     @Test
117     public void testSave() {
118         News news = new News();
119         news.setTitle("AA");
120         news.setAuthor("aa");
121         news.setNewsDate(new Date());
122         //news.setId(100);//不起效果
123         System.out.println(news);
124         //news.setId(101);//拋出異常
125         session.save(news);
126         System.out.println(news);
127     }
128     /**
129      * persist():也會執行insert操作
130      * 和save()的區別:
131      * 在調用persist方法之前,若對象已經有ID了,則不會執行insert,而拋出異常
132      */
133     @Test
134     public void testPsesist() {
135         News news = new News();
136         news.setTitle("DD");
137         news.setAuthor("dd");
138         news.setNewsDate(new Date());
139         //news.setId(200);//拋出異常
140         System.out.println(news);
141         session.save(news);
142         System.out.println(news);
143     }
144     
145     /**
146      * 
147      */
148     @Test
149     public void testGet() {
150         News news = (News) session.get(News.class, 21);
151         System.out.println(news);
152     }
153     
154     /**
155      * get 和   load
156      * 
157      * 1.執行get方法,會立即加載對象。
158      *        而執行load方法,若不使用該對象,則不會立即執行查詢操作,而返回一個代理對象
159      * 
160      *      get是立即檢索,load是延遲檢索
161      * 
162      * 2.load方法可能會拋出LazyInitializationException(懶加載異常):在需要初始化代理對象之前已經關閉了session
163      * 
164      * 3.若數據表中沒有對應的記錄,且session也沒有被關閉。同時需要使用對象時
165      *         get 返回null
166      *         load 若不使用該對象的任何屬性,則不會出問題;若要初始化了,拋出異常
167      * 
168      * 
169      */
170     @Test
171     public void testLoad() {
172         News news = (News) session.load(News.class, 21);
173         System.out.println(news);
174     }
175     
176     /**
177      * update:
178      * 1.若更新一個持久化對象,不需要顯式的調用update對象。因為在調用Transaction的commit方法時,會先執行session的flush方法。
179      * 2.更新一個游離對象,需要顯式的調用session的update方法。可以把一個游離對象變為持久化對象
180      * 
181      * 需要注意的:
182      * 1.無論要更新的游離對象和數據表中的記錄是否一致,都會發送update語句。
183      *      如何能讓update方法不再盲目的發送update語句,在.hbm.xml文件的class節點設置select-before-update的值為true,默認為flase。但通常不需要設置該屬性
184      * 
185      * 2.若數據表中沒有對應的記錄,但還調用了update方法,會拋出異常
186      * 
187      * 3.當update()方法關聯一個游離對象時,如果在Session的緩存中已經存在相同OID的持久化對象,會拋出異常。因為在Session緩存中不能有兩個OID相同的對象
188      */
189     @Test
190     public void testUpdate() {
191         /*News news = (News) session.get(News.class, 22);
192         news.setAuthor("Sun");//此時news的author字段已經更新到數據庫中,因為在執行commit語句時會先執行flush,flush將session緩存中的修改同步到數據庫中。
193         */
194         
195         News news = (News) session.get(News.class, 22);
196         transaction.commit();
197         session.close();
198         
199         session = sessionFactory.openSession();
200         transaction = session.beginTransaction();
201         
202         
203         //news.setAuthor("Sun");
204         session.update(news);
205         
206     }
207     
208     /**
209      * 注意:
210      * 1.若OID不為空,但數據表還沒有和其對應的記錄。會拋出一個異常。
211      * 2.了解:OID值等於id的unsaved-value屬性值的對象,也被認為是一個游離對象
212      */
213     @Test
214     public void testSaveOrUpdate() {
215         News news = new News("FF", "ff", new Date());
216         news.setId(41);
217         session.saveOrUpdate(news);
218         
219     }
220     
221     /**
222      * delete: 執行刪除操作,只要OID和數據表中一條記錄對應,就會准備執行delete操作
223      * 若OID在數據表中沒有對應的記錄,則拋出異常
224      * 
225      * 可以通過設置一個Hibernate配置文件hibernate.use_identifier_rollback 為true,使刪除對象后,把其OID置為null
226      */
227     @Test
228     public void testDelete() {
229         /*//游離對象刪除
230         News news = new News();
231         news.setId(42);
232         
233         session.delete(news);*/
234         
235         //持久化對象刪除
236         News news = (News) session.get(News.class, 41);
237         session.delete(news);//計划刪除,並不立即執行。在commit中的flush時執行delete
238         System.out.println(news);//依然可以打印
239     }
240     
241     /**
242      * evict:從session緩存中把指定的持久化對象移除
243      */
244     @Test
245     public void testEvict() {
246         News news1 = (News) session.get(News.class, 22);
247         News news2 = (News) session.get(News.class, 41);
248         
249         news1.setTitle("AA");
250         news2.setTitle("BB");
251         
252         session.evict(news1);
253     }
254     
255     /**
256      * 調用存儲過程
257      */
258     @Test
259     public void testDoWork() {
260         session.doWork(new Work() {
261             
262             @Override
263             public void execute(Connection connection) throws SQLException {
264                 System.out.println(connection);
265                 //調用存儲過程
266                 
267                 //創建存儲過程的對象  
268                 CallableStatement c = connection.prepareCall("{call getsum(?,?)}");
269                 
270                 //給存儲過程的第一個參數設置值  
271                 c.setInt(1,100);  
272                  
273                 //注冊存儲過程的第二個參數  
274                 c.registerOutParameter(2,java.sql.Types.INTEGER);  
275                  
276                 //執行存儲過程  
277                 c.execute();  
278                 
279                 connection.close();
280             }
281         });
282     }
283 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM