※刪除
Session session = HibernateUtil2.getSession(); try { Query hqlDelete = session.createQuery(" delete from Dept where deptno = :deptno"); hqlDelete.setParameter("deptno", 60); int rtn = hqlDelete.executeUpdate(); if(rtn > 1){ System.out.println("刪除成功!"); } else { System.out.println("無資料可刪除!"); } } catch (Exception e) { System.err.println("例外錯誤!"); e.printStackTrace(); } finally { session.close(); }
※因為hibernate是資料庫和物件的轉換,而HQL是物件的操作,所以必需注意Dept大小寫要和hbm.xml的java類名稱一致,否則會出「xxx is not mapped」的錯誤
※刪除時,from可以不寫
※hibernate-mapping有個屬性auto-import,預設是true,所以Dept才可以不用寫包.類,但如果有兩個以上都是同名,還是會報錯,還有另一種方法,就是使用別名
Dept.hbm.xml
<hibernate-mapping> <import class="vo.Dept" rename="xxx"/> <class> <!-- ... --> </class> </hibernate-mapping>
※這時就可以使用xxx代替Dept了(class一定要包.類),但別名如果和其他的class同名(cfg.xml有設定mapping resource或mapping class),而且auto-import是true或沒設,假設我打Emp,這時就會出「duplicate import: Emp refers to both vo.Dept and vo.Emp (try using auto-import="false")」的錯
※修改
Session session = HibernateUtil2.getSession(); try { Query hqlUpdate = session.createQuery(" update Dept set dname = ?, loc = :loc where deptno = 60 "); hqlUpdate.setString(0, "IT"); hqlUpdate.setString("loc", "zh_CN"); int rtn = hqlUpdate.executeUpdate(); if(rtn > 1){ System.out.println("修改成功!"); } else { System.out.println("無資料可修改!"); } } catch (Exception e) { System.err.println("例外錯誤!"); e.printStackTrace(); } finally { session.close(); }
※Query有很多的setXxx可以用,還可以像刪除那樣,用setParameter,會自動偵測
※Query的第一個參數可用數字或字串,數字從0開始,字串必須對應「:字串」,也可以混用
※混用時必須注意數字(也就是?)必須在字串前面,不然會出「cannot define positional parameter after any named parameters have been defined」的錯
※新增
Session session = HibernateUtil2.getSession(); try { Query hqlInsert = session.createQuery(" insert into Dept(deptno, dname, loc) select 60, 'IT', 'zh_TW' from Emp where empno = 7369 "); int rtn = hqlInsert.executeUpdate(); if(rtn > 1){ System.out.println("新增成功!"); } else { System.out.println("無資料可新增!"); } } catch (Exception e) { System.err.println("例外錯誤!"); e.printStackTrace(); } finally { session.close(); }
※新增不支援values的寫法,這裡的最後一張圖,往上一點點,only開頭的有寫
可能是hibernate一定要先查詢才有辦法做到吧!
※新增時不能用setXxx,像我是寫死的,這個例子舉的不好
※所以大部分新增都是用save()或者是Session的createSQLQuery()達成
※createSQLQuery(),裡面的SQL就是怕hibernate的功能不能達到時,可以根據各家的SQL進行撰寫,而且還加入一些較特殊的用法
※查詢
Session session = HibernateUtil2.getSession(); try { Query hqlQuery = session.createQuery(" from Dept "); List<?> list = hqlQuery.list(); for(Object o:list){ Dept d = (Dept) o; System.out.println(d.getDeptno()); } } catch (Exception e) { System.err.println("例外錯誤!"); e.printStackTrace(); } finally { session.close(); }
※不能寫select *,會說「*」是不認識的字元
※from Dept 等同 select d from Dept d
※List<Object>會出黃黃的警告,所以我用List<?>
※取特定的欄位
Query hqlQuery1 = session.createQuery(" select dname from Dept "); List<?> list = hqlQuery1.list(); for(Object o:list){ System.out.println(o); } Query hqlQuery2 = session.createQuery(" select deptno, dname, loc from Dept "); @SuppressWarnings("unchecked") List<Object[]> list = hqlQuery2.list(); for (Object[] oArray : list) { for (Object o : oArray) { System.out.println(o); System.out.println("-----"); } }
※所以只有一個欄位回傳的是List<Object>;
多個欄位就是List<Object[]>,官方說一條結果返回多個物件叫tuples
※尤於沒有List<?[]>,因為?是什麼都不知道了,怎麼可能還有陣列,所以只好寫List<Object[]>
※將欄位轉換成VO物件
Query hqlQuery = session.createQuery(" select deptno as deptno, dname as dname, loc as loc from Dept "); hqlQuery.setResultTransformer(new AliasToBeanResultTransformer(Dept.class)); List<?> list = hqlQuery.list(); Iterator<?> it = list.iterator(); while(it.hasNext()){ Dept d = (Dept) it.next(); System.out.println(d.getDname()); }
※雖然select的欄位名稱和vo物件一樣,但還是要「as欄位名」,連as都要打,as能省略的只有物件名,如from Dept d,如果不打會出「PropertyNotFoundException: Could not find setter for 0 on class vo.Dept」的錯
※將SQL或HQL分離
※XML設定
hbm.xml
<class name="vo.Dept" table="DEPT"> <!-- ... --> </class> <query name="xxx">from Dept</query> <sql-query name="ooo">SELECT * FROM DEPT</sql-query>
※query name為hql,類似createQuery(); sql-query為sql,類似createSQLQuery()
TestHibernate.java
Query hqlQuery = session.getNamedQuery("xxx"); List<?> listXxx = hqlQuery.list(); for(Object o:listXxx){ Dept d = (Dept)o; System.out.println(d.getDname()); } Query sqlQuery = session.getNamedQuery("ooo"); List<Object[]> listOoo = sqlQuery.list(); for(Object[] oArray:listOoo){ for(Object o:oArray){ System.out.println(o); } }
※Annotation設定
Dept.java@NamedQueries({ @NamedQuery(name = "xxx", query = "from Dept") }) @NamedNativeQueries({ @NamedNativeQuery(name = "ooo", query = "SELECT * FROM DEPT", resultClass=Dept.class) }) @Entity @Table(name = "DEPT", schema = "c##scott") public class Dept { //... }
※sql一定要加resultClass,不然執行時會報「org.hibernate.cfg.NotYetImplementedException: Pure native scalar queries are not yet supported」的錯; 而hql不用,也沒這個選項可設定
TestHibernate.java
Query query = session.getNamedQuery("ooo"); List<?> list = query.list(); for(Object o:list){ Dept d = (Dept)o; System.out.println(d.getDname()); }
※用Annotation時輸出的結果,統一都用hql的寫法才不會報強制轉換的錯誤
※回傳只有一筆
Query hql = session.createQuery(" from Dept where deptno = 20 "); Dept dept1 = (Dept) hql.list().get(0); Dept dept2 = (Dept) hql.uniqueResult(); System.out.println(dept1.getDname()); System.out.println(dept2.getDname());
※使用uniqueResult()看起來較方便
※分頁
Query hql = session.createQuery(" from Emp "); hql.setFirstResult(2);//從第幾筆開始 hql.setMaxResults(3);//一頁顯示幾筆 System.out.println("從0開始,機器的角度"); Iterator<?> it1 = hql.list().iterator(); while (it1.hasNext()) { Emp e = (Emp) it1.next(); System.out.println(e.getEmpno()); } System.out.println("從1開始,人的角度"); Iterator<?> it2 = hql.iterate(); while (it2.hasNext()) { Emp e = (Emp) it2.next(); System.out.println(e.getEmpno()); }
※資料庫的內容
第一個迴圈的結果為: 7521、7566、7654
第二個迴圈的結果為: 7499、7521、7566
※工作時常這樣用
※機器角度的算法:int currentPage = 3;//模擬前端輸入第幾頁 int pageSize = 3; Query hql = session.createQuery(" from Emp "); hql.setFirstResult((currentPage - 1) * pageSize);//公式 hql.setMaxResults(pageSize); Iterator<?> it1 = hql.list().iterator(); while (it1.hasNext()) { Emp e = (Emp) it1.next(); System.out.println(e.getEmpno()); }
※注意setFirstResult的算法
結果為: 7782、7788、7839
人角度的算法:
int currentPage = 3;//模擬前端輸入第幾頁 int pageSize = 3; Query hql = session.createQuery(" from Emp "); hql.setFirstResult(currentPage * pageSize - pageSize + 1);//公式 hql.setMaxResults(pageSize); Iterator<?> it2 = hql.iterate(); while (it2.hasNext()) { Emp e = (Emp) it2.next(); System.out.println(e.getEmpno()); }
結果當然還是和上面一樣
如果在一級或二級快取已有資料,那iterate()比list()快,否則較慢
沒有留言:
張貼留言