HQL语句详解

周总结 同时被 2 个专栏收录
12 篇文章 0 订阅
7 篇文章 0 订阅

什么是HQL呢?

 HQL是Hibernate Query Language的缩写,提供更加丰富灵活、更为强大的查询能力;HQL更接近SQL语句查询语法。同时也提供了更加面向对象的封装。

完整的HQL语句形势如下:
Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc 非常类似标准的SQL语句。

1、 实体查询:

String hql = "from Customer c"; //查询admin实体类所有的数据
List<Customer> list = session.createQuery(hql).list(); //

可以看到所有的关联信息全部查出来了。

上面的代码执行结果是,查询出Customer实体对象所对应的所有数据,而且将数据封装成Admin实体对象,并且放入list中返回。

 因为HQL语句与标准SQL语句相似,所以我们也可以在HQL语句中使用where字句,并且可以在where字句中使用各种表达式,比较操作符以及使用“and”,”or”连接不同的查询条件的组合。
看下面的一些简单的例子:

from User user where user.age=20; //查询年龄为20的用户
from User user where user.age between 20 and 30;//查询年龄在20~30的用户
from User user where user.age in(20,30);//查询年龄为20,或30的用户
from User user where user.name is null;//查询用户姓名为空的用户
from User user where user.name like%zx%;//模糊查询带有“zx”的用户
from User user where (user.age%2)=1;//查询用户年龄为奇数的用户
from User user where user.age=20 and user.name like%zx%;//查询年龄为20,并且姓名带有“zx”的用户

2.实体的更新与删除

  如果我们想将数据库中所有18岁的用户的年龄全部改为20岁,那么我们要首先将年龄在18岁的用户检索出来,然后将他们的年龄修改为20岁,最后调用Session.update()语句进行更新。如下面的代码:

Transaction trans=session.beginTransaction();//创建事务对象
String hql=”update User user set user.age=20 where user.age=18;
Query queryupdate=session.createQuery(hql);
int ret=queryupdate.executeUpdate();//执行更新
trans.commit();//提交任务

3. 属性查询

 很多时候我们在检索数据时,并不需要获得实体对象所对应的全部数据,而只需要检索实体对象的部分属性所对应的数据。这时候就可以利用HQL属性查询技术,如下面程序示例:
1)返回默认查询出来的list里存放的是一个Object数组,还需要转换成对应的javaBean。

String hql = "select c.name,c.account  from Customer c";//查询客户姓名和账号名
Query query = session.createQuery(hql);
List list = query.list();//得到一个list集合
String string = JSON.toJSONString(list);//为了方便直接输出为字符串
System.out.println(string);

如下图:
和上面的实体查询结果对比就知道了,这一次没有把所有的级联数据查出来。

2)第二种方式是通过HQL语句new POJO()实现,方法如下:
注意:创建一个对象必须有对应的构造器,要不然会报错。

String hql = "select new Customer(c.name,c.account,c.password,c.gender,c.identityId,c.tel) from Customer c"

这样就可以直接用对象调用属性打印了。

结果图:

4.分组与排序

 与SQL语句相似,HQL查询也可以通过order by子句对查询结果集进行排序,并且可以通过asc或者desc关键字指定排序方式,和标准的SQL一样默认升序排列,如下面的代码:

String hql = "from Line L order by L.price ";

5.参数绑定

在Hibernate中共存在4种参数绑定的方式,下面我们将分别介绍:
1)按参数名称绑定:
在HQL语句中定义命名参数要用”:”开头,形式如下:

String hql = "from Line L where L.days=:days";//根据天数查询
		Query query = session.createQuery(hql);
		query.setInteger("days",1);//按名字天数绑定
		List<Line> list = query.list();
		for (int i = 0; i < list.size(); i++) {//循环打印
			System.out.println("线路名称:"+list.get(i).getLineName()+"|线路点数:"+list.get(i).getDays()+"|线路价格:"+list.get(i).getPrice());
		}

2)按参数位置邦定:
在HQL查询语句中用”?”来定义参数位置,形式如下:

String hql = "from Line L where L.days=?";//根据天数查询,用?占位符
Query query = session.createQuery(hql);
query.setInteger(0,1);//按名字天数绑定

大家可以看出和1)的方式不同的地方就是参数是用一个==?==占位符代替;然后query方法两个参数第一个是占位符的位置,(从0开始)。如果有多个占位符,那么就他们的位置就是0,1,2,3…

3)setParameter()方法:
在Hibernate的HQL查询中可以通过setParameter()方法邦定任意类型的参数,如下代码:

String hql = "from Line L where L.days=:days";
		Query query = session.createQuery(hql);
		query.setParameter("days", "1");

和第一种的方式区别在于,只能写String类型的数值setParameter(属性名,属性值);

4)setProperties()方法:
在Hibernate中可以使用setProperties()方法,将命名参数与一个对象的属性值绑定在一起,如下程序代码:

Customer customer = new Customer("tz", "111");//
		String hql = "from  Customer c where c.account=:account and c.password=:password ";
		Query query = session.createQuery(hql);
		query.setProperties(customer);
		List<Customer> list = query.list();
		for (int i = 0; i < list.size(); i++) {
			System.out.println("游客id:"+list.get(i).getCustomerId());
		}

setProperties()方法会自动将customer对象实例的属性值匹配到命名参数上,但是要求命名参数名称必须要与实体对象相应的属性同名。

5)setEntity()方法
这里还有一个特殊的==setEntity()==方法,它会把命名参数与一个持久化对象相关联,如下面代码所示:

Customer customer = (Customer)session.get(Customer.class, 1);//获取游客ID为1的持久化对象
		String hql = "from Cart c where c.customer=:customer";
		Query query = session.createQuery(hql);
		query.setEntity("customer", customer);
		List<Cart> list = query.list();
		for (int i = 0; i < list.size(); i++) {
			System.out.println("购物车id:"+list.get(i).getCartId());
		}

总结:对于查询,相比较之下,实体查询属性查询将属性封装成对象的查询方式,前者查询结果会被保存在session的缓存区,只有事务提交过后才会被清除。后者就不存在这种机制,只要系统不在需要它了就会被回收。因此在开发统计查询系统时,尽量使用通过select语句,写出需要查询的属性的方式来返回关系数据,而避免使用第一种查询方式返回持久化对象(这种方式是在有修改需求时使用比较适合),这样可以提高运行效率并且减少内存消耗。


SQL Injection
SQL Injection是一种专门针对SQL语句拼装的攻击方式。之前一直不知道还有这种东西,看完了介绍后自己尝试了一下:

上图是不久前写的一个小项目的客户验证代码截图,也是用的字符串拼接方式。也没与做任何其他的安全措施。
只要能够在库中查询到一个对象就说明验证成功,可是这样就给别人一个sql注入的契机了。
请看下图:我在登录名处输入" tz’ or account ='x ",密码随便打的,因为加了or我的密码就相当于可有可无了,不需要密码正确页可以登录成功。
在这里插入图片描述
debug进入可以看到拼接成了一个只需查用户名就可以登录的sql语句。
在这里插入图片描述
当我们用绑定参数的方式就可以避免这种漏洞了,因为用参数绑定的方式单引号会被当成一个字符串。
下面是我的后台登录,采用绑定参数的方式验证,发现单引号被当成了一个字符,并且被转义了。这样就得不到正确的数据了。
在这里插入图片描述

  • 3
    点赞
  • 1
    评论
  • 10
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

Mr_tz

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值