今天呢,我就詳細的寫着 Hibernate框架的一種檢索方式:Criteria查詢。下面我寫的這些案例,可能對於大牛沒有什麼好看的,可是對於初學者來講,倒是一筆財富。java
首先咱們要知道的檢索方式: 數據庫
Hibernate框架提供了5種檢索對象的方式express
1.導航對象圖檢索方式:根據已經加載的對象導航到其餘對象session
2.OID檢索方式:按照對象的OID來檢索對象app
3.HQL檢索方式:使用面向對象的HQL查詢語言框架
4.QBC檢索方式:使用QBC(Query By Criteria)API來檢索對象,這種API封裝了基於字符串形式的查詢語句,提供了更加面向對象的查詢接口測試
5.本地SQL檢索方式:使用本地數據庫的SQL查詢語句ui
什麼是Criteriathis
Criteria是一種比hql更面向對象的查詢方式。 Criteria 可以使用 Criterion 和 Projection 設置查詢條件。能夠設置 FetchMode(聯合查詢抓取的模式 ) ,設置排序方式,Criteria 還能夠設置 FlushModel (沖刷 Session 的方式)和 LockMode。spa
Criteria查詢 就是 經過面向對象化的設計,將數據查詢條件封裝爲一個對象
Criteria是一個接口,它繼承了 另外一個接口。
它裏面有不少的方法,看圖說話:
有了這些方法,咱們能夠再深度研究,這個方法裏面的參數,有了什麼接口或是類的類型。例如舉個簡單的例子:
對於add的方法,裏面有了一個參數,它的返回類型爲 Criterion。如今咱們再對Criterion研究。
Restrictions類提供了建立Criterion對象的方法。咱們看下圖,它是SimpleExpression ,
可是咱們再耐心的往下看,就知道了
你看到沒有,其實首先呢,Restrictions 建立了SimpleExpression對象,而後SimpleExpression又實現了Criterion。因此Restrictions類提供了 建立Criterion對象的方法。這樣咱們就很清楚了這些接口或類的關係了。
因此,到這裏你們應該清楚,想好一門技術,其實很簡單,就是要不斷的挖掘,堅持的作下去,你就是大牛。
使用Criteria查詢的步驟:
(1).使用Session 接口 的createCriteria()方法建立 Criteria對象。
(2).使用Restrictions類提供的靜態方法設置查詢條件,這些靜態方法返回Criterion對象,一個Criterion對象表明一個查詢條件Criteria接口的add()方法用來添加查詢條件。
(3).使用Criteria接口的list()方法執行查詢語句,list()方法返回java.util.List類型的結果,List集合中的每個元素都是持久化對象。
下面咱們正式經過例子來講明一切。
第一個案例:查詢全部的信息
//1.查詢全部部分信息 private static void selectAllDept() { Session session = HibernateUtil.currentSession(); session.beginTransaction(); Criteria criteria = session.createCriteria(Dept.class); @SuppressWarnings("unchecked") List<Dept> list = criteria.list(); for (Dept dept : list) { System.out.println("部門編號:"+dept.getDeptNo()+","+"部門名稱:"+dept.getdName()); } session.getTransaction().commit(); HibernateUtil.closeSessio(); }
代碼解釋:session.createCriteria()方法建立Criteria對象,createCriteria()方法的參數是持久化類的類型,使用criteria.list()執行的查詢語句,list()方法的返回值是List集合。
第二個案例:Criteria帶條件查詢 查詢部門名稱爲「開發部」的部門
private static void selectToCriteriaOfDeptNo() { Session session = HibernateUtil.currentSession(); session.beginTransaction(); Criteria criteria = session.createCriteria(Dept.class); Criterion criterion = Restrictions.eq("dName", "開發部"); criteria.add(criterion); @SuppressWarnings("unchecked") List<Dept> list =criteria.list(); for (Dept dept : list) { System.out.println("部門編號:"+dept.getDeptNo()+","+"部門名稱:"+dept.getdName()); } session.getTransaction().commit(); HibernateUtil.closeSessio(); }
代碼解釋:Restrictions.eq()方法設定條件,eq()方法的第一個參數是持久化類的屬性,第二個參數是條件,返回值是Criterion對象。
第三個案例:關聯查詢 查詢「開發部」全部員工
/* * createCriteria() * * @SuppressWarnings("unchecked") List<Employee> list = session.createCriteria(Employee.class) .add(Restrictions.ilike("ename", "a", MatchMode.ANYWHERE)) .createCriteria("dept") .add(Restrictions.eq("dName", "開發部").ignoreCase()) .list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()+","+"部門名稱:"+employee.getDept().getdName()); }*/ /* createAlias * @SuppressWarnings("unchecked") List<Employee> list = session.createCriteria(Employee.class,"emp") .createAlias("dept", "d") .add(Restrictions.ilike("emp.ename", "a", MatchMode.ANYWHERE)).add(Restrictions.eq("d.dName", "開發部") .ignoreCase()).list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()+","+"部門名稱:"+employee.getDept().getdName()); } */ @SuppressWarnings("unchecked") List<Dept> list = session.createCriteria(Dept.class,"d") .setFetchMode("emps", FetchMode.JOIN) .add(Restrictions.eq("d.loc", "北京").ignoreCase()) .list(); /*for (Dept dept : list) { System.out.println("部門名稱:"+dept.getdName()+","+dept.getLoc()+","+dept.getEmps().size()); }*/ //過濾掉重複的數據 HashSet<Dept> set=new HashSet<Dept>(list); for (Dept dept : set) { System.out.println("部門名稱:"+dept.getdName()+","+dept.getLoc()+","+dept.getEmps().size()); } session.getTransaction().commit(); HibernateUtil.closeSessio();
第四個案例:範圍 查詢地址爲bj或者sh的員工信息
Criteria criteria = session.createCriteria(Emp.class); //1.2 Collection的實現類 List<String> lists=new ArrayList<String>(); lists.add("bj"); lists.add("sh"); Criterion criterion=Restrictions.in("empCity", lists); //1.2 criteria.add(criterion); criteria.add(criterion); List<Emp> list = criteria.list(); for (Emp emp : list) { System.out.println(emp.getEmpName()); }
第五個案例:字符串模式匹配,查詢員工地址中包含「s」的全部員工
Criteria criteria = session.createCriteria(Emp.class); Criterion criterion = Restrictions.like("empCity", "%b%"); criteria.add(criterion); List<Emp> list = criteria.list(); for (Emp emp : list) { System.out.println(emp.getEmpName()); }
第六個案例:邏輯運算 and 過濾 查找地址是bj 而且 名稱中包含 「雨」 的員工信息
Criteria criteria= session.createCriteria(Emp.class); Criterion c1 = Restrictions.eq("empCity", "bj"); Criterion c2= Restrictions.like("empName", "號",MatchMode.ANYWHERE); Criterion criterion = Restrictions.and(c1, c2); criteria.add(criterion); List<Emp> list = criteria.list(); for (Emp emp : list) { System.out.println(emp.getEmpName()); }
第七個案例:集合運算集合運算 查詢 沒有員工的部門
Criteria criteria = session.createCriteria(Dept.class); Criterion criterion = Restrictions.isEmpty("emps"); criteria.add(criterion); List<Dept> list = criteria.list(); for (Dept dept : list) { System.out.println(dept.getDeptName()); }
第八個案例:
動態查詢
* 如何查找出符合如下條件的員工信息:
職位是工程師,如:job = ‘engineer’
工資大於2000元,如:salary > 2000
入職時間在2006年12月31日至2008年12月31日之間
如何查找出符合如下條件的員工信息:
地址 = ‘bj’
員工編號大於0
Session session = HibernateUtil.currentSession(); session.beginTransaction(); //1.準備對象的封裝條件 EmployeeCondition empcon=new EmployeeCondition(); empcon.setEmpno(21); empcon.setEname("張三"); //2.添加動態條件 Criteria criteria = session.createCriteria(Employee.class); if(empcon.getEname()!=null){ criteria.add(Restrictions.like("ename", empcon.getEname(),MatchMode.EXACT)); } if(empcon.getEmpno()!=null){ criteria.add(Restrictions.eq("empno", empcon.getEmpno())); } //3.執行查詢 @SuppressWarnings("unchecked") List<Employee> list = criteria.list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()); } session.getTransaction().commit(); HibernateUtil.closeSessio();
第九個案例:
排序 addOrder()
* 查詢工號大於0的員工,查詢結果按員工 編號升序排列
Session session = HibernateUtil.currentSession(); session.beginTransaction(); Criteria criteria = session.createCriteria(Employee.class); SimpleExpression expression = Restrictions.gt("empno", 2); @SuppressWarnings("unchecked") List<Employee> list = criteria .add(expression) .addOrder(Order.asc("empno")) .list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()); } /*@SuppressWarnings("unchecked") List<Employee> list=(List<Employee>) criteria.add( Restrictions.gt("empno", 2)).addOrder(Order.asc("empno")).list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()); }*/ session.getTransaction().commit(); HibernateUtil.closeSessio();
第十個案例:
分頁
* Criteria接口提供了設置分頁的方法
setFirstResult(int firstResult) 起始記錄的索引
setMaxResult(int maxResult) 最大記錄條數
//10.分頁 查詢員工表中的4-6條數據,每頁3條數據
Criteria criteria = session.createCriteria(Emp.class); //總記錄數 //新的類型 :條件(Restrictions) Projections //1.1 Projection projection = Projections.count("empId"); //1.2 criteria.setProjection(projection); //1.3 Integer count = ((Long)criteria.uniqueResult()).intValue(); System.out.println(count); //預置2個變量 int pageSize=3; int pageIndex=2; criteria.setFirstResult((pageIndex-1)*pageSize); criteria.setMaxResults(pageSize); List<Emp> list = criteria.list(); for (Emp emp : list) { System.out.println(emp.getEmpName()); }
或是下面這個:
Criteria criteria = session.createCriteria(Employee.class) .add(Restrictions.eq("deptNo", 1)) .setProjection(Projections.count("empno")); Integer count = (Integer) criteria.uniqueResult();//查詢總記錄數 //分頁 int pageSize=2;//每頁顯示的記錄數 int totalpages=(count%pageSize==0)?(count/pageSize):(count/pageSize+1);//總頁數 int pageIndex=1;//當前頁號 criteria = session.createCriteria(Employee.class) .add(Restrictions.eq("deptNo", 1)) .addOrder(Order.desc("empno")); @SuppressWarnings("unchecked") List<Employee> list = criteria. setFirstResult((pageIndex-1)*pageSize) .setMaxResults(pageSize) .list(); for (Employee employee : list) { System.out.println("員工編號:"+employee.getEmpno()+","+"員工名稱:"+employee.getEname()); System.out.println("總記錄數:"+totalpages); System.out.println("總記錄數:"+pageIndex); } session.getTransaction().commit(); HibernateUtil.closeSessio();
第十一個案例:
DetachedCriteria和Criteria功能相似,它實現了CriteriaSpecification接口
Criteria是由Session對象建立的
DetachedCriteria建立時不須要Session對象
使用DetachedCriteria來構造查詢條件
能夠把DetachedCriteria做爲方法參數傳遞給業務層
* 查詢開發部的員工
//1.構建一個Detached對象 DetachedCriteria detachedCriteria=DetachedCriteria.forClass(Emp.class); //1.2 別名 detachedCriteria.createAlias("dept", "d"); //1.3 指定檢索條件 Criterion criterion = Restrictions.eq("d.deptName", "開發部"); //bind 綁定 detachedCriteria.add(criterion); //detachedCriteria的方法植入對session的引入 List<Emp> list = detachedCriteria.getExecutableCriteria(session).list(); for (Emp emp : list) { System.out.println(emp.getEmpName()); } }
在這十幾案例中,這個案例算是最重要的了,看似代碼少,可是 DetachedCriteria很是重要,在之後公司若是用的到的話,都是用DetachedCriteria 類的一些方法實現查詢的。Criteria 和 DetachedCriteria 的主要區別在於建立的形式不同, Criteria 是在線的,因此它是由 Hibernate Session 進行建立的;而 DetachedCriteria 是離線的,建立時無需Session,DetachedCriteria 提供了 2 個靜態方法 forClass(Class) 或 forEntityName(Name)進行DetachedCriteria 實例的建立。
DetachedCriteria有以下方法:
第十二案例:查詢惟一對象
Session session = HibernateUtil.currentSession(); session.beginTransaction(); Employee employee = (Employee) session.createCriteria(Employee.class) .add(Restrictions.isNotNull("empno")) .addOrder(Order.desc("empno")) .setMaxResults(1) //若是有多個對象,不設這個的話,會報異常,NonUniqueResultException .uniqueResult(); System.out.println(employee.getEmpno()+","+employee.getEname()); session.getTransaction().commit(); HibernateUtil.closeSessio();
注意:若是有多個對象的時候,必定要寫setMaxResults(1) 方法,限制條數,不然會報以下異常:
第十三個案例:投影
Session session = HibernateUtil.currentSession(); session.beginTransaction(); // setProjection() /* List<String> list = session.createCriteria(Dept.class).setProjection(Property.forName("dName")).list(); for (String deptName : list) { System.out.println(deptName); }*/ //Projections.projectionList() @SuppressWarnings("unchecked") List<Object[]> list = session.createCriteria(Dept.class) .setProjection(Projections.projectionList() .add(Property.forName("loc")) .add(Property.forName("dName"))).list(); for (Object[] obj : list) { System.out.println("地址:"+obj[0]+"," +"名稱:"+obj[1]); } session.getTransaction().commit(); HibernateUtil.closeSessio(); }
經過上面的十幾個案例,能夠大體對Criteria查詢有些瞭解,能夠再去深刻的瞭解Ciiteria 查詢的其餘方法,能瞭解的更廣!!
能夠經過上面的例子,咱們能夠看到Restrictions 有了不少的方法,如今來總結一下:
只要咱們把Restrictions的這些方法搞定,就差很少了。。。
第二部分 :註解
Hibernate 提供了Hibernate Annootations 擴展包,它能夠替換複雜的hbm.xml文件,使得Hibernate 程序的開發大大簡化。即利用註解後,可不用定義持久haunted類的*.hbm.xml文件,而直接以註解方式寫入持久化類的實現中。
做用:它能夠代替配置文件,大大簡化代碼量,代碼可讀性比較高,編寫的工做量比較輕。
使用註解的步驟:
1.添加jar包
01.hibernate-annotations-3.4.0.GA根目錄下的hibernate-annotations.jar
02.hibernate-annotations-3.4.0.GA\lib目錄下的hibernate-commonons-annotations.jar,ejb3-persitence.jar.
注意:
在hibernate中,一般配置對象關係映射關係有兩種,一種是基於xml的方式,另外一種是基於annotation的註解方式
熟話說,蘿蔔青菜,可有所愛,每一個人都有本身喜歡的配置方式,這兩種方式,發現使用annotation的方式能夠更簡介,經過annotation來配置各類映射關係,在hibernate4之後已經將annotation的jar包集成進來了,若是使用hibernate3的版本就須要引入annotation的jar包。
2.使用註解配置持久化類及對象關聯關係。
3.使用AnnotationsConfiguration創建會話工廠。
sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
4.在配置文件(hibernate.cfg.xml)中聲明持久化類
<mapping resource="cn/entity/Dept.hbm.xml" />
基礎知識:
1.@Entity註釋指名這是一個實體Bean。 2.@Table註釋指定了Entity所要映射帶數據庫表 3.@Table.name()用來指定映射表的表名 4.若是缺省@Table註釋,系統默認採用類名做爲映射表的表名 5.實體Bean的每一個實例表明數據表中的一行數據,行中的一列對應實例中的一個屬性
* initialValue 初值 * sequenceName 序列的名稱 * strategy 策略 * @Column註釋定義了將成員屬性映射到關係表中的哪一列和該列的結構信息 * secondaryTable:從表名。若是此列不建在主表上(默認是主表),該屬性定義該列所在從表的名字 * GenerationType.SEQUENCE 根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。(這個值要與generator一塊兒使用) * generator 指定生成主鍵使用的生成器(多是orcale中的序列)。 * @SequenceGenerator —— 註解聲明瞭一個數據庫序列。該註解有以下屬性 : * name 表示該表主鍵生成策略名稱,它被引用在@GeneratedValue中設置的 「gernerator」值中 * sequenceName 表示生成策略用到的數據庫序列名稱。 * initialValue 表示主鍵初始值,默認爲0. * allocationSize 每次主鍵值增長的大小,例如設置成1,則表示每次建立新記錄後自動加1,默認爲50. * SEQUENCE:使用數據庫德SEQUENCE列萊保證惟一(Oracle數據庫經過序列來生成惟一ID) * name:映射的列名 * */
6.@Column註釋定義了將成員屬性映射到關係表中的哪一列和該列的結構信息 1)name:映射的列名。如:映射tbl_user表的name列,能夠在name屬性的上面或getName方法上面加入; 2)unique:是否惟一; 3)nullable:是否容許爲空; 4)length:對於字符型列,length屬性指定列的最大字符長度; 5)insertable:是否容許插入; 6)updatetable:是否容許更新; 7)columnDefinition:定義建表時建立此列的DDL; 8)secondaryTable:從表名。若是此列不建在主表上(默認是主表),該屬性定義該列所在從表的名字。 7.@Id註釋指定表的主鍵,它能夠有多種生成方式: 1)TABLE:容器指定用底層的數據表確保惟一; 2)SEQUENCE:使用數據庫德SEQUENCE列萊保證惟一(Oracle數據庫經過序列來生成惟一ID); 3)IDENTITY:使用數據庫的IDENTITY列萊保證惟一; 4)AUTO:由容器挑選一個合適的方式來保證惟一; 5)NONE:容器不負責主鍵的生成,由程序來完成。 @GeneratedValue註釋定義了標識字段生成方式。 @Temporal註釋用來指定java.util.Date或java.util.Calender屬性與數據庫類型date、time或timestamp中的那一種類型進行映射。 @Temporal(value=TemporalType.TIME)
廢話很少說,案例解釋一切:
@OneToOne :創建持久化類之間的一對一關聯關係
持久化類:
IdCard
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name="IdCard") public class IdCard { @Id //限定長度爲18位,至關於約束 @Column(length=18) private String cid; @Column(name="cname") private String cname; //mappedBy 表示由 craid所在的對象維護關聯關係 @OneToOne(mappedBy="craid") private Student stu; public IdCard() { } public String getCid() { return cid; } public void setCid(String cid) { this.cid = cid; } public IdCard(String cid, String cname, Student stu) { super(); this.cid = cid; this.cname = cname; this.stu = stu; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; }
Student:
import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.CollectionId; @Entity @Table(name="MyStudent") public class Student { //標示屬性 @Id //使用默認的序列 Hibernate_Sequence @GeneratedValue private Integer id; @Column(name="name") private String name; //一對一關聯 保存學生的時候自動保存身份證對象 @OneToOne(cascade={CascadeType.ALL}) //在底層的MyStudent數據表中植入的列名 @JoinColumn(name="cid") private IdCard craid; public Student() { super(); } public Student(Integer id, String name, IdCard craid) { super(); this.id = id; this.name = name; this.craid = craid; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public IdCard getCraid() { return craid; } public void setCraid(IdCard craid) { this.craid = craid; }
hibernate.cfg.xml:
<mapping class="cn.happy.entity.Student"/> <mapping class="cn.happy.entity.IdCard"/>
測試代碼:
Session session = HibernateUtils.currentSession(); session.beginTransaction(); Student stu=new Student(); stu.setName("李四"); IdCard cid=new IdCard(); cid.setCid("123321311111111111"); stu.setCraid(cid); session.save(cid); session.save(stu); session.getTransaction().commit(); HibernateUtils.closeSession(); }
@OneToMany:創建持久化類之間的一對多關聯關係
Dept:
@Entity @Table(name="Dept") public class Dept { @Id //引用生成器 @GeneratedValue private Integer deptNo; //默認Hibernate管理 private String deptName; @OneToMany(mappedBy="dept") @LazyCollection(LazyCollectionOption.FALSE) private Set<Emp> emps=new HashSet<Emp>();
Emp:
@Entity @Table public class Emp { @Id private Integer empId; @Column private String empName; @ManyToOne @JoinColumn(name="deptNo") private Dept dept;
測試代碼:
Session session = HibernateUtils.currentSession(); Transaction tx = session.beginTransaction(); // Dept dept = (Dept)session.load(Dept.class, 21); // // System.out.println(dept.getDeptName()); Emp emp = (Emp)session.load(Emp.class, 21); System.out.println(emp.getEmpName()); tx.commit(); HibernateUtils.closeSession();
@ManyToMany:創建持久化類之間的多對多關係
Emp:
@Entity @Table(name="YEmp") public class Emp { @Id @GeneratedValue private Integer eid;//員工編號 private String ename;//員工名稱 //建立鏈接表 @ManyToMany(cascade=CascadeType.ALL) @JoinTable( name="YEmpPro", joinColumns=@JoinColumn(name="eid"), inverseJoinColumns=@JoinColumn(name="pid") ) private Set<Project> pros=new HashSet<Project>();//員工對應的項目
Project:
* * 項目表 * */ @Entity @Table(name="YProject") public class Project { @Id @GeneratedValue private Integer pid;//項目編號 private String pname;//項目名稱 @ManyToMany(mappedBy="pros")//將控制權轉交給主表 private Set<Emp> emps=new HashSet<Emp>();//員工對應的項目
測試代碼:
Session session; Transaction tx; @Before public void mybefore(){ session= HibernateUtils.currentSession(); tx=session.beginTransaction(); } @After public void myafter(){ tx.commit(); HibernateUtils.closeSession(); } /** * 1.1 保存部門 */ @Test public void groupTest(){ Emp emp1=new Emp("李四"); Emp emp2=new Emp("王五"); Project p1=new Project("項目一"); Project p2=new Project("項目二"); emp1.getPros().add(p1); emp1.getPros().add(p2); emp2.getPros().add(p2); session.save(emp1); session.save(emp2); }
一些註解的解釋:
mappedBy="dept":設置了維繫關係的控制權交給Emp類的這一方,至關於Dept.hbm.xml配置文件的inverse="true",mappedBy屬性值dept是Emp類中的屬性名。
cascade屬性的聯級操做:
到這裏就差很少了,經過上面的案例,咱們明顯能夠看到,註解比配置文件要簡單的多,代碼量少,方便維護。