(十二)Hibernate的查询方式
一、OID检索方式
按照对象的OID来查询对象。Session的get/load方法提供了这种功能。 如果应用程序中事先知道了OID,就可以使用这种查询对象的方式。
二、导航对象图检索方式
根据已经加载的对象,导航到其他对象. 例如,对于已经加载的Customer对象,可以导航到所有关联的Order对象
三、HQL检索方式
简介:
使用面向对象的HQL查询语言。Hibernate提供了Query接口,它是专门的HQL查询接口,能执行各种复杂的HQL语句。
HQL是面向对象的查询语言,和SQL查询语言有些类似,Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。HQL封装了JDBC的细节
HQL和SQL本质是不一样的: -HQL查询语言面向对象,Hibernate负责解析HQL语句,然后根据映射文件,把HQL语句翻译成SQL语句。HQL查询语句中主体是类和类的属性。 -SQL查询语言是和关系数据库绑定在一起的,SQL查询语句中主体是数据库表和表的字段。
HQL查询的步骤
-通过session的createQuery(HQL语句)方法创建一个Query对象
-调用Query的list()方法执行查询语句。该方法返回List集合
(1)================= 查找所有对象 ====================
public class Demo { private Session session; @Test public void test() { //读取配置文件 Configuration conf=new Configuration().configure(); //根据配置创建factory SessionFactory sessionfactory=conf.buildSessionFactory(); session = sessionfactory.openSession(); Transaction ts=session.beginTransaction(); //HQL语句是面向对象的,from 类名 List<Customer> customerlist=session.createQuery("from Customer").list(); System.out.println(customerlist); ts.commit(); session.close(); sessionfactory.close(); } }
(2)================= HQL语句使用别名 ====================
例如:List< Customer > customerlist=session.createQuery(“from Customer as c”).list(); as关键字用来设置别名,as也可以省略。 from Customer c即可。
(3)================= HQL语句选择查询 ====================
选择查询是指仅查找某些属性。 这时list()返回的集合中包括的是一个一个数组,每个数组中是一条记录。 List <Object[]> customerlist=session.createQuery("select id,name from Customer").list(); for(Object[] obj:customerlist){ System.out.println(Arrays.toString(obj)); }
(4)================= HQL语句投影查询 ====================
基于选择查询的基础上,把查询到的属性封装到对象中,该对象的其他属性为null。 该对象必须有对应的构造方法。 List <Customer> customerlist=session.createQuery("select new Customer(id,name) from Customer").list(); for(Customer c:customerlist){ System.out.println(c.toString()); } Customer类中必须有如下构造方法 public Customer(Integer id, String name) { this.id = id; this.name = name; }
(5)================= HQL对查询结果排序 ====================
HQL语言使用order by关键字对结果进行排序。 asc为升序,desc为降序。 List <Customer> customerlist=session.createQuery("select new Customer(id,name) from Customer order by id desc").list();
(6)================= HQL分页查询 ====================
-setFirstResult(int index):设定从第几个对象开始检索,起始值为0。 -setMaxResult(int count):设定一次检索的对象数目。默认情况下检索所有的对象。 Query query=session.createQuery("select id,name from Customer"); //从第一个对象开始 query.setFirstResult(0); //查找两个对象 query.setMaxResults(2); List result=query.list();
(7)================= HQL语句中绑定参数 ====================
对于实际应用中,经常需要用户输入一些查询条件,我们返回符合查询条件的数据。 我们可以使用from Customer where name='"+name+"';来实现 但是这种方式是非常不安全的,会受到SQL注入等非法攻击。
Hibernate中使用参数绑定来避免以上问题。有两种方式 (1)使用?占位符绑定 占位符的索引从0开始。 Query query=session.createQuery("from Customer where id=?"); query.setInteger(0, 7); Customer c=(Customer) query.uniqueResult(); System.out.println(c.toString()); Query提供了各种绑定数据类型的参数的方法setXxx(),如果参数为字符串类型,就调用setString(),如果参数为整数类型,就调用setInteger()等等。 这些setXxx()方法第一个参数代表占位符的索引,第二个代表参数值。 (2) 使用参数名字绑定 在HQL中使用命名参数,命名参数以":"开头。 Query query=session.createQuery("from Customer where id=:a"); query.setInteger("a", 7); Customer c=(Customer) query.uniqueResult(); System.out.println(c.toString()); 这些setXxx()方法第一个参数是命名参数的名字,第二个参数是值。
(8)================= HQL查询单个对象 ====================
-uniqueResult()方法:返回单个对象 Query query=session.createQuery("from Customer where id=1"); Customer c=(Customer) query.uniqueResult(); System.out.println(c.toString());
(9)================= HQL聚合函数和分组查询 ====================
(1)HQL调用聚合函数 -查询customer表所有记录数目 Query query=session.createQuery("select count(*) from Customer"); //该语句返回long类型 Long c=(Long) query.uniqueResult(); System.out.println(c.intValue()); -查询最大ID Query query=session.createQuery("select Max(id) from Customer"); Integer c=(Integer) query.uniqueResult(); System.out.println(c.intValue()); (2)分组查询 group by子句用来分组查询。 -根据id分组,统计相同id的数目 Query query=session.createQuery("select id,count(*) from Customer group by id"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -having子句用于为分组查询加上条件 Query query=session.createQuery("select id,count(*) from Customer group by id having id>8"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); }
(10)================= HQL连接查询 ====================
-交叉连接:返回被连接的两个表所有数据行的笛卡儿积 如果A表有5行记录,B表有7行记录,返回的结果就有35行记录 显然,会产生很多没有意义的数据。 Query query=session.createQuery("from Customer,Order"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -隐式内连接 在交叉连接基础上,通过条件来过滤一些无意义的数据,达到内连接的效果。 Query query=session.createQuery("from Customer c,Order o where o.customer=c"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -显式内连接 使用inner join关键字表示内连接。inner可以省略,只使用join。 调用list()方法返回的集合中存放的是每个元素对应的记录,每个元素都是数组类型。 Query query=session.createQuery("from Customer c inner join c.orders"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -迫切内连接 使用inner join fetch关键字表示迫切内连接。 调用list()方法返回的集合中存放的是Customer对象的引用,每个Customer对象的Orders集合都被初始化,存放所有关联的Order对象。 Query query=session.createQuery("from Customer c inner join c.orders"); List <Object> list=query.list(); for(Object obj:list){ System.out.println(obj); } -左外连接 在连接查询中,连接左端的表中的所有的行全部显示,并且能在右端的表中找到匹配的行,如果右端表中没能找到左端匹配的行,则对应NULL. 使用left join关键字表示左外连接。 返回的list集合中存放的是多个对象数组。 Query query=session.createQuery("from Customer c left join c.orders"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -迫切左外连接 使用left join fetch关键字表示迫切左外连接。 list()方法返回的集合中存放的是Customer对象的引用,每个Customer的Orders集合都被初始化,存放关联的Order对象。 Query query=session.createQuery("from Customer c left join fetch c.orders"); List<Object> list=query.list(); for(Object obj:list){ System.out.println(obj); } -右外连接 和左外连接一样,连接右端表中的行全部显示,连接左端找到匹配的行,如果未能找到匹配的行,则用NULL代替 使用right join关键字表示右外连接。 Query query=session.createQuery("from Customer c right join c.orders"); List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } -迫切右外连接 Query query=session.createQuery("from Customer c right join fetch c.orders"); List<Object> list=query.list(); for(Object obj:list){ System.out.println(obj); }
(11)================= 在映射文件中定义命名查询语句 ====================
前面的例子中,HQL查询语句都写在程序代码中。Hibernate允许在映射文件中定义字符串形式的查询语句。 <class name="com.cad.domain.Customer" table="customer" > <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" column="name"></property> <set name="orders" batch-size="3" fetch="subselect"> <key column="cid"/> <one-to-many class="com.cad.domain.Order" /> </set> <!--定义局部命名查询语句--> <query name="bcd"><![CDATA[from Order]]></query> </class> <!--定义全局命名查询语句--> <query name="abc"><![CDATA[from Customer]]></query> //调用全局的命名查询语句 Query query=session.getNamedQuery("abc"); //调用局部的命名查询语句 Query query=session.getNamedQuery("com.cad.domain.Customer.bcd"); List<Object> list=query.list(); for(Object obj:list){ System.out.println(obj); }
四、QBC检索方式
使用QBC(Query By Criteria)API检索对象。封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口。 QBC检索方式的步骤 -调用Session的createCriteria()方法创建一个Criteria对象 -设定查询条件 -调用Criteria接口的list()方法执行查询语句。返回List集合。
(1)================= 查询所有对象 ====================
//传递类名.class即可 Criteria criteria=session.createCriteria(Customer.class); List<Customer> l=criteria.list(); for(Customer c:l){ System.out.println(c); }
(2)================= QBC对查询结果进行排序 ====================
QBC使用org.hibernate.criterion.order类对查询结果排序。 asc为升序,desc为降序。 Criteria criteria=session.createCriteria(Customer.class); criteria.addOrder(org.hibernate.criterion.Order.desc("id")); List<Customer> l=criteria.list(); for(Customer c:l){ System.out.println(c); }
(3)================= QBC分页查询 ====================
QBC的分页查询和HQL类似。Criteria接口也提供了方法。 -setFirstResult(int index):设定从第几个对象开始检索,起始值为0。 -setMaxResult(int count):设定一次检索的对象数目。默认情况下检索所有的对象。 Criteria criteria=session.createCriteria(Customer.class); criteria.setFirstResult(0); criteria.setMaxResults(2); List<Customer> l=criteria.list(); for(Customer c:l){ System.out.println(c); }
(4)================= QBC设定查询条件 ====================
必须创建一个Criterion对象来设定查询条件。Restrictions类提供了创建Criterion的方法。 -Restrictions.eq() 等于 -Restrictions.ne() 不等于 -Restrictions.gt() 大于 ..........等等很多方法 Criteria criteria=session.createCriteria(Customer.class); //查询id为7的Customer Criterion c1=Restrictions.eq("id", 7); criteria.add(c1); Customer c=(Customer) criteria.uniqueResult(); System.out.println(c);
(5)================= QBC检索单个对象 ====================
uniqueResult():返回单个对象
五、本地SQL检索方式
可以使用原生的SQL语句来进行查询。 本地SQL检索也是使用Query接口,通过Session的createSQLQuery(SQL语句)方法来创建Query。 例子: Query query =session.createSQLQuery("select * from customer"); List<Object[]> list=query.list(); for(Object[] o:list){ System.out.println(Arrays.toString(o)); } 默认情况下,SQLQuery返回的list集合中存放的是关系数据。每个元素都是Object[]数组。 -addEntity()方法能把查询结果中每一行的数据封装成对象 Query query =session.createSQLQuery("select * from customer").addEntity(Customer.class); List<Customer> list=query.list(); for(Customer o:list){ System.out.println(o.toString()); }