使用 Hibernate 进行 CURD 操作时候,插入、更新、删除操作可以直接通过对持久化实体(PO)实例来进行,对于查询操作,Hibernate 提供了以下3种方式来进行:
- HQL 查询;
- Criteria 条件查询(hibernate 5.x 已经废弃);
- SQL 查询;
Hibernate HQL查询
HQL(Hibernate Query Language)
是Hibernate提供的一种面向对象的查询语言,语法类似于SQL;
SQL 的操作对象是数据表、列等数据库对象,HQL 的操作对象是类、实例、属性等;
HQL 的基本使用
HQL 查询依赖于 Query 类,每一个 Query 对应一个查询对象;
Query 类支持链式调用,常用的 API 如下:
Query | createQuery(String HQLString) | 根据 HQL 语句创建 Query 实例 |
Query | setXX(String key,XX xx) | hibernate 5.2 以前的方式传递参数方式:设置 HQL 语句中的参数 ,如 setInteger(String key,Integer value),setString(String key,String value)等 |
Query | setParameter(String key,Object value) setParameter(int position,Object val) | hibernate5.2 之后的传递参数的方式,具体用法见下面; |
Query | setFirstResults(int index) | 设置返回的结果集从第几条记录开始 |
Query | setMaxResults(int maxNum) | 设置本次放回结果集的最大结果数目 |
List | list() | 返回查询的结果列表,以 List<Object> 的方式,返回列表中的每一个 Object 对应一条查询结果记录,可能是一个PO持久化实体,也可能是一个包含所有返回属性的 Object[] 数组; |
基本示例
其中实体 Users 的建模如下:
Entity | Users |
Property | int id String name Date createDate String icon |
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.List;
public class TestHQL {
public static void main (String[] args) throws Exception{
//创建session,开启事务
Session session = HibernateUitl.currentSession();
Transaction tran = session.beginTransaction();
/*查询示例1: 直接查询整个实体 */
String hqlStr = "select u from Users as u " + //hql查询模板
"where u.icon = :iconType ";
List list = session.createQuery(hqlStr) //创建Query对象
.setParameter("iconType","1") //设置hql模板参数
.list(); //获取结果
for(Object element : list){ //遍历结果
Users user = (Users)element;
System.out.println(user.getName()+" "+user.getCreateDate());
}
/*查询示例2:查询实体中的部分属性 */
String hqlStr2 = "select u.name ,u.icon from Users as u " +
"where u.createDate between :startDate and :endDate";
List list2 = session.createQuery(hqlStr2)
.setParameter("startDate",new SimpleDateFormat("yyyy-MM-dd").parse("2017-01-11"))
.setParameter("endDate",new Date())
.list();
for(Object element : list2){ //遍历结果
Object[] objs = (Object[])element;
System.out.println(objs[0]+" "+objs[1]);
}
//提交事务,关闭session
tran.commit();
HibernateUtil.closeSession();
}
}
HQL语句模板和参数设置
HQL语句一般使用模板的方式编写,以提高灵活性,类似与 JDBC 中的PreparedStatement ,当然也可以直接填写参数;
HQL 模板的占位符 有2种方式,一种为 “:N” 占位符(N为参数变量),一种为“?”占位符;
//方式1
String hqlStr = "select u from Users as u " +
"where u.icon = :iconType "; //:iconType 指明一个命名为“iconType”的参数
List list = session.createQuery(hqlStr)
.setParameter("iconType","1") // 设置模板中参数“iconType”的值为"1"
.list();
//方式2
String hqlStr2 = "select distinct u from Users as u " +
"where u.icon = ? "; //? 指明一个参数
List list2 = session.createQuery(hqlStr2)
.setParameter(0,"1") //设置模板中第1个参数的值为“1”;
.list();
Query 返回结果列表
Query 返回的结果是
以 List<Object> 的方式返回,返回List中的每一个 Object 对应一条查询结果记录;
这个 Object 可以是一个PO持久化实体(在查询结果可以转化为某个PO持久化实体时),也可以是一个包含所有返回属性的 Object[] 数组,如以上基本示例中的2个示例;
HQL 的基本语法
HQL 语句的语法基本类似于SQL,大部分 SQL99 中的关键字可以通用于 HQL 语句,HQL支持以下语法:
这些语法和 SQL99 中是基本一样的;
Select [distinct] 实体实例/实体属性
from 实体类 [as] 实体示例名(别名)
where 查询条件
order by 实体属性 [asc / desc]
group by 实体属性
having 分组条
示例
//查询User类实例中 age > 12 的实例,依据 icon 属性分组,每个分组以 age 升序排序,返回所有符合要求的实例
select u from User u
where u.age > 12
order by u.age asc
group by u.icon
//查询User实例中以 name 属性以 'A' 开头的实例,返回所有符合要求的实例的 name,id 属性
select u.name u.id from User u
where u.name like "A%"
HQL 中的聚合函数
HQL 支持在选出的属性上使用聚合函数,这些函数和SQL中的完全相同,如:
avg ,count,max,min,sum;
示例:
//查询User实例中 age>12 的数量
select count(u) from User u
where u.age > 12
HQL 中的条件表达式
HQL where子句中支持 SQL 的所有运算符,同时也支持 EJB-QL 的运算符;
SQL 运算符 | 数学运算符::+ - * / 等; 二进制运算符:= 、>、<、!= 、like 等; 逻辑运算符:and、or、not 等; 字符串连接符,函数:|| (如 str || str2),concat(str1,str2) 其他运算符:in、not in、between、is null 、is not null、is empty、is not empty、member of、not member of 等 时间操作函数:current_time()、current_date()、current_timestamp()、second()、minute()、hour()等 |
EJB-QL 运算符 | substring()、trim()、lower()、upper()、length()、locate()、abs()、sqrt()、bit_length()等 |
关联连接
HQL 支持两种方式的关联连接(join)方式:隐式(implict)、显式(explict);
在使用时优先推荐使用显式连接,隐式连接在 hibernate 3.2 之后 只能自动作用与普通的组件属性和1-1的关联实体,对于1-N、N-N的关联实体只能通过显式连接,隐式连接直接通过"."调用关联对象,底层会自动转化为 SQL99 的 交叉连接;
以下介绍显式连接:
1)关联连接类型:
- inner join / join : 内连接
- left join:左外连接
- right join:右外链接
- full join:全连接
※ 注意这些连接类型都会在底层转化为相应的SQL,前提条件是这些数据库要能支持这些关联连接操作;
2)关联连接基本语法
select 实体实例/实体属性 from 实体 [as] 实体实例(别名)
inner join 关联实体 [as] 关联实体实例(别名)
with 提供额外的关联连接条件,类似于SQL中的on
示例:
//User实体和Article实体之间的关联关系为 双向1-N,User中含有属性 Set<Article> atricles
//查找发布Article的数量>10 的 User
Select u from User
inner join u.articles a
where count(a) > 10
//同上,同时连接时 User.id > Article.id
Select u from User
inner join u.articles a
with u.id > a.id
where count(a) > 10
3)解决关联实体延迟加载的问题
对于集合属性,hibernate 默认采用延迟加载的策略。比如User中含有一个集合属性 articles,当User被加载时,默认不加载 articles,当 User 所在的 Session 被关闭时,User的实例将无法访问其关联的 articles。为了解决这个问题,有两种方式:
① 在关联实体的注解标签中,设置属性
fetch=FetchType.EAGER;
② 在相关的HQL中使用
fetch 关键字,如下:
select u from User u
inner join fetch u.articles
※ fetch 关键字无法与 Query.
setMaxResults() ,Query.setFirstResults() 方法共用;
※ full join fetch ,right join fetch 没有任何意义;
子查询
HQL 提供的子查询语法类似于 SQL,类似如下:
//查询 User中age大于平均的实例
select oldUser from User oldUser
where oldUser.age > (Select avg(u.age) from User u)
HQL 命名查询
Hibernate 支持将 HQL 语句放置到持久化实体的注解中,通过这种方式能进一步提高程序的解耦;
命名查询使用 @NamedQuery 标签,可以将多个 @NamedQuery 放置到一个 @NamedQueries 中 ,示例使用如下:
User.java
@Entity
@Table(name="users")
@NamedQuery(name="query1",query="select u from Users u where icon = :iconType")
public class Users {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="user_id")
private int id;
@Column(name="create_date")
@Temporal(TemporalType.DATE)
private Date createDate;
......
}
Test.java
public class TestHQL {
public static void main (String[] args) throws Exception{
Session session = HibernateUtil.currentSession();
Transaction tran = session.beginTransaction();
List list = session.getNamedQuery("query1") //调用命令查询
.setParameter("iconType","3")
.list();
.....
}
}
DML风格的批量更新/删除
HQL 语句除了可以用于查询外,也可以用与批量 update,insert,如下:
public static void main(String[] args){
Session session = HibernateUtil.currentSession();
Transaction tran = session.beginTransaction();
//更新数据
String hqlUpdate = "update User u set u.point = u.point + :increasePoint";
int updateCount = session.createQuery( hqlUpdate)
.setParameter("increasePoint",12)
.executeUpdate();
//删除数据
String hqlDelete = "delete from User where point < :lowesrPoint";
int deletedCount = session.createQuery(hqlDelete)
.executeUpdate();
tran.commit();
HibernateUtil.closeSession();
}