Hibernate学习详解(2: HQL实用技术
HQL语句
Hibernate 支持三种查询方式 : HQL查询 Criteria查询 原生SQL查询
HQL查询是Hibernate查询语言(Hibernate Query Language) 一种面向对象的查询语言, 与SQL(结构化查询语言不同)
其中没有表 和 字段的概念, 只有对象和属性的概念; (本次学习方向)
HQL语句形式上和SQL语句相似, 但又有不同…HQL是面向对象的可以理解为多态, 继承 关联…Criteria查询 采用面向对象的方式构造查询;
原生SQL查询 直接执行SQL语句的查询,可以在SQL语句中根据不同的数据库进行特殊对应查询 ( 函数 序列等…)
常用HQL
注意:
HQL语句对: Java类和属性区分大小写..!! 对其它大小写不影响;
因为:Hibernate中, 对每一个Java实体类已经在数据库中对应了数据库的一个表...
使用HQL查询时, 只需要使用对应的Java类,就相当于是对表的操作....
类名相当于表名 类中属性对应表中的列
From
from查询全部: 相当于查询, 该Java类对应的表的所有数据!! as 或 空格 起别名;
from Java类名
from Java类名 as 别名
from Java类名 别名
Select
select 用于选取查询对应的列:select 比较特殊后面讲解~
select 属性 from 类名;
select 别名.属性1,别名,属性2 from 类名 别名;
where
where子句用于表达式查询的限制条件: 根据条件查询, 或 非空条件;
from 类名 where 属性 = “”;
from 类名 where 属性 is not null;
表达式
表达式一般使用在where 子句中…
from 类名 where lower(字符类型属性)=“sadasd”; lower()表示匹配改列属性不区分大小写…
form 类名 where year(时间类型属性)=“1999”; year()取出时间类型的年份进行比较; 还有很多需要善于学习…
order by子句
order by用于按指定属性(列) 进行排序
from 类名 order by 属性 desc|asc
指向HQL
执行HQL语句的步骤
获取Session对象
编写 HQL语句
创建Query对象
执行查询,得到查询结果: Hibernate中提供两种方式都是Query对象的 list() 和 iterate();
关键代码: 实例Demo> hibernate实现增删改查续写
DeptDao.java
//list方法
public void queryList(){
//获取Session对象
Session session = hibernateUtil.openSession();
//编写 HQL语句
String hql = "from Dept";
//创建Query对象
Query query = session.createQuery(hql);
//执行查询,得到查询结果: Hibernate中提供两种方式都是Query对象的 list() 和 iterate();
List<Dept> list = query.list();
//关闭资源
hibernateUtil.closeSessionn(session);
//遍历结果
for (Dept dept : list) {
System.out.println(dept);
}
}
//iterate方法
public void queryiterate(){
//获取Session对象
Session session = hibernateUtil.openSession();
//编写 HQL语句
String hql = "from Dept";
//创建Query对象
Query query = session.createQuery(hql);
//执行查询,得到查询结果: Hibernate中提供两种方式都是Query对象的 list() 和 iterate();
Iterator<Dept> Iterator = query.iterate();
//遍历iterate 迭代器;
while(Iterator.hasNext()){
Dept dept = Iterator.next();
System.out.println(dept);
}
//关闭资源: iterate()属于懒加载最后关闭!!
hibernateUtil.closeSessionn(session);
}
//自主在Test.java类中测试
list() 和 iterate() 区别:
都是hibernate 的实现查询方法, 根据 From 类名;返回对应的泛型类型;
list() 返回list<> 集合;
iterate() 返回 Iterator<> 迭代器; (需要对迭代器有一部分了解~)
iterate() 属于懒加载
, 且iterate() 的查询方式与 list() 不同.
list() 一次性执行Hql 结果集存储在list()中;查询一次;
iterate() 会先从数据库获取到对应的主键值,在根据主键一条一条的查询对应的数据!! 查询多次
iterate() 优点,会缓存数据, 所以不建议一次的使用,对于经常查询的数据可以考虑iterate()…
在HQL语句中绑定参数
哈哈, 对于参数你们怎么像呢?
在HQL 中拼接参数吗?
public void CS(String name){
//省略...
String hql = "from Dept where dname='"+name+"'";
//省略...
}
的确可行, 但并不好 性能低, 且不安全, 考虑SQL注入… 解决方案↓↓↓↓
Hibernate 中提供两种方式参数绑定 使用占位符
按参数位置绑定
按参数名称绑定
DeptDao.java
//根据dname 查询();
public void query(String dname) {
Session session = hibernateUtil.openSession();
//定义hql
//String hql = "from Dept where dname like ?"; // ?占位符
String hql = "from Dept where dname like :dname"; // 起别名形式
Query query = session.createQuery(hql);
//query.setString(0,dname); // ?占位符: setxxx(int,xxx类型); int对于占位符的下标 0开始,Obejct对应的值;
query.setString("dname", "%"+dname+"%"); // 起别名形式: setxxx(String,xxx类型); String对应的别名,Objetc对应的值;
List<Dept> list = query.list();
hibernateUtil.closeSessionn(session);
for (Dept dept : list) {
System.out.println(dept);
}
}
//对于多个参数还可以使用Object[] 来进行处理...
public void queryall(Object[] ob) {
Session session = hibernateUtil.openSession();
//定义hql
String hql = "from Dept where dname like ? and loc like ?"; // ?占位符
Query query = session.createQuery(hql);
//通过遍历Object[] 集合数组形式来完成占位符的赋值...
if(ob!=null && ob.length>0){
for (int i = 0; i < ob.length; i++) {
query.setParameter(i,ob[i]); //根据数组下标,0开始,且Object可以是所有类型;
}
//setParameter(int,Object); 根据占位符下标.完成占位符赋值..
}
List<Dept> list = query.list();
hibernateUtil.closeSessionn(session);
//遍历结果...
for (Dept dept : list) {
System.out.println(dept);
}
}
//setParameter(int,Object); 可以通过下标来给占位符赋值;
//setParameter(String,Object); 其实也有根据别名来完成赋值的方法,但是并不是很方便遍历(别名和值两个数组进行遍历..)...而Hibernate有更好的方法: setProperties(Object);
public void queryPoroerties(Dept dept){
Session session = hibernateUtil.openSession();
//定义hql
String hql = "from Dept where dname like :dname"; //使用别名进行赋值,这里使用对象所以 别名必须要和类的属性名对应!!
Query query = session.createQuery(hql);
//setProperties(类对象类型);
query.setProperties(dept); //使用对象直接进行赋值...注意hql别名要和属性名对应!
List<Dept> list = query.list();
hibernateUtil.closeSessionn(session);
for (Dept d : list) {
System.out.println(d);
}
}
Test.java
DeptDao ddDao = new DeptDao();
// ddDao.query("");
// Object[] ob = new Object[2];
// ob[0]="%%"; //因为数值太少就啥也不填了,模糊查询直接写%号
// ob[1]="%%";
// ddDao.queryall(ob);
Dept dept = new Dept();
dept.setDname("%%");
ddDao.queryPoroerties(dept);
Hibernate 中提供两种方式参数绑定: 按参数位置绑定 按参数名称绑定
setXXX():针对具体数据类型
setXXX( int position, XXX类型 value); 为 ?占位符下标进行赋值…
setXXX( int position, XXX类型 value); 为指定 别名, 进行赋值…
setParameter():任意类型参数
setParameter( int position, Object value); 为 ?占位符下标进行赋值…可以将值定成一个Object[] 进行遍历…
setParameter( String name, Object value); 为指定 别名, 进行赋值… 不是很方便遍历Hibernate提供方法: setProperties(Object);
setProperties():专为命名参数定制
setProperties(Obeject); 参数是一个对象类型,使用时以对象的属性名 当作 别名进行赋值运行…
setProperties(Map); Map 以键值对形式, 键当作别名参数与Hql执行…
…还有很多善于发现
实现动态查询
动态SQL
以前学习 Mybatis时候了解过,根据提供的条件判断而产生不同的SQL语句执行出不同的结果;
对程序有一定的优化~通用性高…
Hibernate 中可以实现动态SQL
DeptDao.java
//动态sql
//根据输入的dname模糊查询如果没输入就查全部
public void queryD(Dept dept){
Session session = hibernateUtil.openSession();
String hql = "from Dept where 1=1"; // where 1=1方便后面拼接条件的 and/or;
//动态条件判断
if(dept.getDname()!=null && dept.getDname().length()>0){
hql+=" and dname like :dname"; //空一格 拼接小细节~ dname注意对象中要存在对应属性名哦~
}
//将拼接好的 HQL进行执行;
Query query = session.createQuery(hql);
query.setProperties(dept); //直接进行赋值...
List<Dept> list = query.list();
hibernateUtil.closeSessionn(session);
for (Dept d : list) {
System.out.println(d);
}
}
Test.java
Dept dept = new Dept();
dept.setDname("%人%");
ddDao.queryD(dept);
虽说上面实例很鸡肋! 但大概原来如此…
Query接口方法
uniqueResult() 唯一结果 及 分页;
使用uniqueResult();获得唯一结果:
相比于 list iterate 都是返回的集合类型;而对于只返回一条的数据返回集合 并不适合;
*uniqueResult(); 返回值 Object类型;
对于只返回一条的记录可以使用… 在进行对于的强制类型转换. 相比返回集合该方法更适合!
DeptDao.java
public void queryUnique(){
Session session = hibernateUtil.openSession();
String hql = "select count(*) from Dept";
Query query = session.createQuery(hql);
Long count = (Long)query.uniqueResult();
hibernateUtil.closeSessionn(session);
System.out.println("总共"+count+"条数据");
}
分页
在之前学习过程中:
分页需要使用复杂的 SQL语句实现, 最关键的是对于不同数据库的分页方式又不同;
Mysql的 limit SqlServer的 top Oracle的rownum
Hibernate中提供:
setFirstResult() :设置从第几条开始
setMaxResults():设置读取最大记录数
有点类似于 mysql的limit …
DeptDao.java
//模拟分页
public void queryPage(Integer dye,Integer hang){ //dye当前页 hang每页行数;
Session session = hibernateUtil.openSession();
String hql = "from Dept";
Query query = session.createQuery(hql);
//对于分页,以下代码应该都了解不详细介绍了...
//设置结果集中的起始位置
query.setFirstResult((dye-1)*hang);
//设置所需的数据数;
query.setMaxResults(hang); //如果不指定所需行数则是后面所有数据....
List<Dept> depts = query.list();
hibernateUtil.closeSessionn(session);
//遍历集合..
for (Dept dept : depts) {
System.out.println(dept);
}
}
Test.java
ddDao.queryPage(1,2); //单纯调用方法();
使用投影
有时候数据展示, 并不需要对象的全部属性, 而是只需要对象中的某一个或几个属性;
又或要通过表达式,聚合函数 得到某些结果…可以使用投影
投影使用的是HQL的Select语句而不是 from
对于投影,查询结果将会有三种情况;
DeptDao.java
/*投影
* 当查询结果仅包含一个结果列,每个结果将作为一个Object的对象返回;
* 当查询结果不止一个结果列 ,每个结果将作为一个Object[]的数组返回;
* 还可以使用 类的构造函数 ,类确定每次返回的对象类型;
* */
public void query1() {
Session session = hibernateUtil.openSession();
String hql = "select dname from Dept"; //查询Dept2表的所有dname名;
Query query = session.createQuery(hql);
//因为返回只有一个列Object类型,定义为 String字符类型可以代表很多...
List<String> list = query.list();
hibernateUtil.closeSessionn(session);
//遍历
for (String string : list) {
System.out.println(string);
}
}
public void query2() {
Session session = hibernateUtil.openSession();
String hql = "select dname,loc from Dept"; //查询Dept2表的所有dname名 和 loc ;
Query query = session.createQuery(hql);
//因为返回有多个列Object[]类型;
List<Object[]> list = query.list();
hibernateUtil.closeSessionn(session);
//遍历
for (Object[] objects : list) {
System.out.println(objects[0]+""+objects[1]);
}
}
public void query3() {
Session session = hibernateUtil.openSession();
String hql = "select new Dept(dname,loc) from Dept"; //根据类的构造函数进行返回对应类型对象;
Query query = session.createQuery(hql);
//使用类的构造进行查询,将返会的是 对应类型的集合...
List<Dept> list = query.list();
hibernateUtil.closeSessionn(session);
//遍历
for (Dept dept : list) {
System.err.println(dept);
}
}
Test.java
//调用各个查询语句;
ddDao.query1();
ddDao.query2();
ddDao.query3();
注意别忘了实体类还需要的有参构造 **Dept.java**
//为投影查询,返回对象类型提供的有参构造
public Dept(String dname, String loc) {
super();
this.dname = dname;
this.loc = loc;
}