(十二)Hibernate的查询方式
一、OID检索方式
1 2 3 | 按照对象的OID来查询对象。Session的get/load方法提供了这种功能。 如果应用程序中事先知道了OID,就可以使用这种查询对象的方式。 |
二、导航对象图检索方式
1 2 3 | 根据已经加载的对象,导航到其他对象. 例如,对于已经加载的Customer对象,可以导航到所有关联的Order对象 |
三、HQL检索方式
简介:
使用面向对象的HQL查询语言。Hibernate提供了Query接口,它是专门的HQL查询接口,能执行各种复杂的HQL语句。
HQL是面向对象的查询语言,和SQL查询语言有些类似,Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。HQL封装了JDBC的细节
1 2 3 4 5 | HQL和SQL本质是不一样的: -HQL查询语言面向对象,Hibernate负责解析HQL语句,然后根据映射文件,把HQL语句翻译成SQL语句。HQL查询语句中主体是类和类的属性。 -SQL查询语言是和关系数据库绑定在一起的,SQL查询语句中主体是数据库表和表的字段。 |
HQL查询的步骤
-通过session的createQuery(HQL语句)方法创建一个Query对象
-调用Query的list()方法执行查询语句。该方法返回List集合
(1)================= 查找所有对象 ====================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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语句使用别名 ====================
1 2 3 | 例如:List< Customer > customerlist=session.createQuery(“from Customer as c”).list(); as关键字用来设置别名,as也可以省略。 from Customer c即可。 |
(3)================= HQL语句选择查询 ====================
1 2 3 4 5 6 7 | 选择查询是指仅查找某些属性。 这时list()返回的集合中包括的是一个一个数组,每个数组中是一条记录。 List <Object[]> customerlist=session.createQuery( "select id,name from Customer" ).list(); for (Object[] obj:customerlist){ System.out.println(Arrays.toString(obj)); } |
(4)================= HQL语句投影查询 ====================
1 2 3 4 5 6 7 8 9 10 11 12 13 | 基于选择查询的基础上,把查询到的属性封装到对象中,该对象的其他属性为 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对查询结果排序 ====================
1 2 3 4 | HQL语言使用order by关键字对结果进行排序。 asc为升序,desc为降序。 List <Customer> customerlist=session.createQuery( "select new Customer(id,name) from Customer order by id desc" ).list(); |
(6)================= HQL分页查询 ====================
1 2 3 4 5 6 7 8 9 | -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语句中绑定参数 ====================
1 2 3 | 对于实际应用中,经常需要用户输入一些查询条件,我们返回符合查询条件的数据。 我们可以使用from Customer where name= '"+name+"' ;来实现 但是这种方式是非常不安全的,会受到SQL注入等非法攻击。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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查询单个对象 ====================
1 2 3 4 5 | -uniqueResult()方法:返回单个对象 Query query=session.createQuery( "from Customer where id=1" ); Customer c=(Customer) query.uniqueResult(); System.out.println(c.toString()); |
(9)================= HQL聚合函数和分组查询 ====================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ( 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连接查询 ====================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | -交叉连接:返回被连接的两个表所有数据行的笛卡儿积 如果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)================= 在映射文件中定义命名查询语句 ====================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 前面的例子中,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检索方式
1 2 3 4 5 6 | 使用QBC(Query By Criteria)API检索对象。封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口。 QBC检索方式的步骤 -调用Session的createCriteria()方法创建一个Criteria对象 -设定查询条件 -调用Criteria接口的list()方法执行查询语句。返回List集合。 |
(1)================= 查询所有对象 ====================
1 2 3 4 5 6 | //传递类名.class即可 Criteria criteria=session.createCriteria(Customer. class ); List<Customer> l=criteria.list(); for (Customer c:l){ System.out.println(c); } |
(2)================= QBC对查询结果进行排序 ====================
1 2 3 4 5 6 7 8 9 | 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分页查询 ====================
1 2 3 4 5 6 7 8 9 10 11 | 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设定查询条件 ====================
1 2 3 4 5 6 7 8 9 10 11 12 | 必须创建一个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检索单个对象 ====================
1 | uniqueResult():返回单个对象 |
五、本地SQL检索方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 可以使用原生的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()); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)