Hibernate 把對象分爲 4 種狀態:java
¨ 持久化狀態,sql
¨ 臨時狀態,數據庫
¨ 遊離狀態,數組
¨ 刪除狀態.緩存
Session 的特定方法能使對象從一個狀態轉換到另外一個狀態session
¨ 在使用代理主鍵的狀況下, OID 一般爲 nullapp
¨ 不處於 Session 的緩存中函數
¨ 在數據庫中沒有對應的記錄測試
¨ OID 不爲 nullspa
¨ 從一個 Session實例的緩存中刪除
¨ Session 已經計劃將其從數據庫刪除, Session 在清理緩存時, 會執行 SQL delete 語句, 刪除數據庫中的對應記錄
¨ 通常狀況下, 應用程序不應再使用被刪除的對象
¨ OID 不爲 null
¨ 位於 Session 緩存中
¨ 持久化對象和數據庫中的相關記錄對應
¨ Session 在清理緩存時, 會根據持久化對象的屬性變化, 來同步更新數據庫
¨ 在同一個 Session 實例的緩存中, 數據庫表中的每條記錄只對應惟一的持久化對象
¨ OID 不爲 null
¨ 再也不處於 Session 的緩存中
¨ 通常狀況需下, 遊離對象是由持久化對象轉變過來的, 所以在數據庫中可能還存在與它對應的記錄
對象的狀態轉換圖
測試hibernate中java對象的狀態
程序代碼 |
生命週期 |
狀態 |
tx = session.beginTransaction(); Customer c = new Customer); |
開始生命週期 |
臨時狀態 |
Session.save(c) |
處於生命週期中 |
轉變爲持久化狀態 |
Long id=c.getId(); c = null; Customer c2 = (Customer)session.load(Customer.class,id); tx.commit(); |
處於生命週期中 |
處於持久化狀態 |
session.close(); |
處於生命週期中 |
轉變爲遊離態 |
c2.getName(); |
處於生命週期中 |
處於遊離態 |
c2 = null; |
結束生命週期 |
結束生命週期 |
|
Session緩存存在對應的記錄 |
數據中存在對應的記錄 |
臨時態 |
no |
no |
持久態 |
yes |
可能有也可能沒有 |
遊離態 |
no |
可能有(數據沒有刪除)也可能沒有 |
Session 的 save() 方法使一個臨時對象轉變爲持久化對象。
¨ Session 的 save() 方法完成如下操做:
¨ Hibernate 經過持久化對象的 OID 來維持它和數據庫相關記錄的對應關係. 當 News 對象處於持久化狀態時, 不容許程序隨意修改它的 ID
@Test public void save() throws Exception{ Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); user = new User();//臨時狀態 user.setName("張張"); session.save(user);//持久化狀態 tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } user.setName("王王");//遊離狀態 System.out.println(user.getName()); }
Session 的 update() 方法使一個遊離對象轉變爲持久化對象, 而且計劃執行一條 update 語句。
@Test public void update() throws Exception{ Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); user = (User) session.get(User.class, 1); //session.clear(); //session.evict(user);//清楚某一個對象。 user.setName("馮芬1"); //session.update(user);//執行完才提交給數據庫 session.flush();//一執行當即提交 System.out.println("執行"); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }Session 的 update() 方法使一個遊離對象轉變爲持久化對象, 而且計劃執行一條 update 語句。
若但願 Session 僅當修改了 News 對象的屬性時, 才執行 update() 語句, 能夠把映射文件中 <class> 元素的 select-before-update(更新以前先查詢) 設爲 true. 該屬性的默認值爲 false
當 update() 方法關聯一個遊離對象時, 若是在 Session 的緩存中已經存在相同 OID 的持久化對象, 會拋出異常
緣由是:兩個不一樣的對象擁有相同的OID
當 update() 方法關聯一個遊離對象時, 若是在數據庫中不存在相應的記錄, 也會拋出異常
該方法同時包含save和update方法,若是參數是臨時對象就用save方法,若是是遊離對象就用update方法,若是是持久化對象就直接返回。
斷定對象爲臨時對象的標準
¨ Java 對象的 OID 爲 null
¨ 映射文件中爲 <id> 設置了 unsaved-value 屬性, 而且 Java 對象的 OID 取值與這個 unsaved-value 屬性值匹配(在hbn3中基本用不到了)
@Test public void saveOrUpdate() throws Exception { Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); //臨時對象執行插入 // user = new User(); // user.setName("洋洋"); // session.saveOrUpdate(user); //遊離對象執行修改 // user = (User) session.get(User.class,1); // session.evict(user); // session.saveOrUpdate(user); //若是是持久化對象就直接返回,不執行操做 user = (User) session.get(User.class,1); session.saveOrUpdate(user); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }
若是參數是臨時對象就會用save方法
若是是遊離對象就用update方法
若是是持久化對象就直接返回,不執行操做
斷定對象爲臨時對象的標準
¨ Java 對象的 OID 爲 null
¨ 映射文件中爲 <id> 設置了 unsaved-value 屬性, 而且 Java 對象的 OID 取值與這個 unsaved-value 屬性值匹配,執行插入操做
根據以上判斷臨時對象的標準id=null是臨時對象。但能夠定義屬性爲int id
* 此時id默認值是0而不是null,應該執行更新操做
* 但實際咱們要執行的插入操做。這時,能夠在id中設置unsaved-value=0(默認值)
均可以根據給定的 OID 從數據庫中加載一個持久化對象
@Test public void getOrLoad() throws Exception { Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); //get方式會立刻執行sql語句 user = (User) session.get(User.class,1); System.out.println("aaaaa"); System.out.println(user.getName()); //load方式不會立刻執行sql語句 user = (User) session.load(User.class,2); System.out.println("bbbbbbbbbbbb"); System.out.println(user.getName()); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }
區別:
¨ 當數據庫中不存在與 OID 對應的記錄時, load() 方法拋出 ObjectNotFoundException 異常, 而 get() 方法返回 null
¨ 二者採用不一樣的延遲檢索策略
get():獲取數據,是持久化狀態
1. 會生成:select ... where id=?
2. 會立刻執行sql語句
3. 若是數據不存在,就返回null
load():獲取數據,是持久化狀態
1.會生成:select ... where id=?
2. load()後返回的是一個代理對象,要求類不能是final的,不然不能生成子類代理,就不能使用懶加載功能了。
3.讓懶加載失效的方式:1、把實體寫成final的;2、在hbm.xml中寫<class ... lazy="false">
4. 不會立刻執行sql語句,而是在第1次使用非id或class屬性時執行sql。
5. 若是數據不存在,就拋異常:ObjectNotFoundException
Session 的 delete() 方法既能夠刪除一個遊離對象, 也能夠刪除一個持久化對象。
¨ 若是參數是持久化對象,就執行一個delete語句,若爲遊離對象,先使遊離對象被session關聯,使他變爲持久化對象
¨ 計劃執行一條 delete 語句
¨ 把對象從 Session 緩存中刪除, 該對象進入刪除狀態.
Session.save(c);
Session.flush();
Session.refresh(c);
------------------------------------------------------
觸發器的行爲致使緩存與數據庫中的數據不一致。解決辦法是執行完
操做後,當即調用session的flush方法和refresh方法,迫使緩存與
數據庫同步。
Session的update操做方法盲目的激活觸發器
若是遊離狀態的對象的屬性和數據庫一致,則更新操做是多餘的。
爲避免這種狀況:
<class name=「」 table=「」 select-before-update=「true」>
……
</class>
,Hibernate 提供經過 Hibernate 查詢語言(HQL)來執行大
批量 SQL 風格的 DML 語句的方法。
UPDATE 和 DELETE 語句的僞語法爲:( UPDATE | DELETE ) FROM? EntityName (WHERE
where_conditions)?。
要注意的事項:
•在 FROM 子句(from-clause)中,FROM 關鍵字是可選的
•在 FROM 子句(from-clause)中只能有一個實體名,它能夠是別名。若是實體名是別名,那麼
任何被引用的屬性都必須加上此別名的前綴;若是不是別名,那麼任何有前綴的屬性引用都是
非法的。
•不能在大批量 HQL 語句中使用 joins 鏈接(顯式或者隱式的都不行)。不過在 WHERE 子句中
可使用子查詢。能夠在 where 子句中使用子查詢,子查詢自己能夠包含 join。
•整個 WHERE 子句是可選的。
使用 Query.executeUpdate() 方法執行一個 HQL UPDATE語句
由 Query.executeUpdate() 方法返回的整型值代表了受此操做影響的記錄數量
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.createQuery( hqlDelete )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
6.HQL介紹
SQL(表和字段) HQL(對象和屬性)
使用HQL查詢
HQL: Hibernate Query Language.
特色:
1,與SQL類似,SQL中的語法基本上均可以直接使用。
2,SQL查詢的是表和表中的列;HQL查詢的是對象與對象中的屬性。
3,HQL的關鍵字不區分大小寫,類名與屬性名是區分大小寫的。
4,SELECT能夠省略.
案例:
1,簡單的查詢
hql = "FROM Employee";
hql = "FROM Employee AS e"; 使用別名
hql = "FROM Employee e"; 使用別名,as關鍵字可省略
執行查詢
List list = session.createQuery(hql).list();
顯示結果
while(itr.hasNext()){ //System.out.println(itr.next().getName()); Object[] object = (Object[]) itr.next(); System.out.println(object[0]+":"+object[1]); }
2,帶上過濾條件的(可使用別名):Where
hql = "FROM Employee WHERE id<10"; hql = "FROM Employee e WHERE e.id<10"; hql = "FROM Employee e WHERE e.id<10 AND e.id>5";
3,帶上排序條件的:Order By
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name"; hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC"; hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";
4,指定select子句(不可使用select *)
hql = "SELECT e FROM Employee e"; 至關於"FROM Employee e" hql = "SELECT e.name FROM Employee e"; 只查詢一個列,返回的集合的元素類型就是這個屬性的類型 hql = "SELECT e.id,e.name FROM Employee e"; 查詢多個列,返回的集合的元素類型是Object數組 hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; 可使用new語法,指定把查詢出的部分屬性封裝到對象中
5,執行查詢,得到結果(list、uniqueResult、分頁 )
Query query = session.createQuery("FROM Employee e WHERE id<3"); query.setFirstResult(0); query.setMaxResults(10); List list = query.list(); 查詢的結果是一個List集合 Employee employee = (Employee) query.uniqueResult(); 查詢的結果是惟一的一個結果,當結果有多個,就會拋異常 System.out.println(employee);
6,函數的使用
hql = "select count(id) from Department"; Number num = (Number) session.createQuery(hql).uniqueResult(); System.out.println(num);
7,分組查詢
hql = "select d.name,count(d.name) from Department d group by d.name"; hql = "select d.name,count(d.name) from Department d group by d.name having count(d.name)>5";
8,參數查詢
第一種:使用「?」
hql = "from Department d where d.id between ? and ? "; List list = session.createQuery(hql) .setParameter(0, 2) .setParameter(1, 8) .list();
第二種:使用變量名
hql = "FROM Employee e WHERE id BETWEEN :idMin AND :idMax"; List list = session.createQuery(hql)// .setParameter("idMax", 15)// .setParameter("idMin", 5)// .list();
第三種:當參數是集合時,使用setParameterList()設置參數值
hql = "FROM Employee e WHERE id IN (:ids)"; List list = session.createQuery(hql)// .setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })// .list();
9在映射文件配置HQL語句
爲了使程序具備更大的靈活性,Hibernate能夠在映射文件中配置HQL語句。以下所示爲在Student.hbm.xml中的配置。
<hibernate-mapping> <class name="hibernate.ch06.Student" table="student" catalog="joblog"> <!--此處省略了配置--> </class> <query name="searchStudent"><![CDATA[ from Student s where s.sage>22 ]]>(<![CDATA[ ]]>表示一些特殊字符不須要轉義) </query> </hibernate-mapping>
能夠用以下代碼訪問配置文件中的HQL語句。
Session session=HibernateSessionFactory.currentSession();//建立Session Query query=session.getNamedQuery("searchStudent"); //用getNamedQuery獲得查詢 List list=query.list(); //執行查詢 Iterator it=list.iterator(); while(it.hasNext()){ Student stu=(Student)it.next(); System.out.println(stu.getSname()); }
其中,getNamedQuery()函數用來訪問映射文件Student.hbm.xml中配置的HQL語句,參數爲配置的名稱。
Select s.id,s.name, c.name from t_student s,t_classes c where c.id = s.classId
Select s.id,s.name, c.name from t_student s right join t_classes c on s.classtId = c.id;
10.鏈接查詢
//第一種:(內鏈接) //hql = "select s.id,s.name,c.name from Student s join s.classes c"; //第二種: //hql = "select s.id,s.name,s.classes.name from Student s"; //外鏈接: hql = "select s.id,s.name,c.name from Student s right join s.classes c"; hql = "select s.id,s.name,c.name from Student s left join s.classes c";
11.更新
//更新前: Student student = (Student)session.get(Student.class, 2); System.out.println(student.getName()); int num = session.createQuery("update Student s set s.name=? where s.id=2") .setParameter(0,"好人1") .executeUpdate(); System.out.println(num); //更新後: session.refresh(student); System.out.println(student.getName());
12.刪除
/*int num1 = session.createQuery("delete Student s where s.id=1") .executeUpdate(); System.out.println(num1);*/
Criteria查詢方式
// 建立Criteria對象 Criteria criteria = session.createCriteria(Student.class); // 增長過濾條件 criteria.add(Restrictions.ge("id", 2)); criteria.add(Restrictions.le("id", 5)); // 增長排序條件 criteria.addOrder(Order.desc("id")); criteria.addOrder(Order.desc("name")); // 執行查詢 // criteria.setFirstResult(0); // criteria.setMaxResults(100); // criteria.uniqueResult(); // criteria.list() List list = criteria.list(); Iterator itr = list.iterator(); while(itr.hasNext()){ Student student = (Student)itr.next(); System.out.println(student.getName()+":"+student.getScore()); }
寫完了 今天落枕了 起牀也是在牀底睜開眼 歪着脖子寫了折磨一一篇, 真難受啊 不過這質量算是我寫過最棒的一篇了吧.