1.hibernate 查询方式
-
- 对象导航查询
一个对象关联了另一个对象,并且两者是一对多的关系,那么通过一个(一方)对象就可以找到另外一个(多方)对象。例如:由一个班级就可以找到班上所有的学生,这种通过班级对象找到学生对象的查询方式就叫做对象导航查询。
- 对象导航查询
-
- OID 查询
又称对象唯一标识符查询。根据对象属性中的唯一标识值来查询这个对象,session 的 get() 方法还有下面说到的 load() 方法,都是 OID 的查询方式。
- OID 查询
-
- HQL 查询
使用 Query 对象调用相关的方法来做查询,需要写相关的hql语句,这是 hibernate 提供的查询语言,hql 语句中写的是实体类和属性,而 sql 语句中写的是数据表和字段。
- HQL 查询
-
- QBC 查询
使用 Criteria 对象调用相关的方法做查询,但是不需要写语句,调用的是方法,操作的也是实体类和属性。
- QBC 查询
-
- SQL 查询
使用 SQLQuery 对象写普通的 sql 语句来做查询,但由于数据库的不同,sql 语句也有所不同,所以一般不使用这种查询方式。但如果需要底层数据库的 SQL 方言查询时,还是可以使用这种方式的。hibernate 种也封装了 SQL 查询的对象 SQLQuery。
- SQL 查询
2.基本代码
下面的例子也是基于班级和学生一对多关系说明的。
2.1 实体类代码
- 学生实体类
package cc.wenshixin.entity;
public class Student {
private Integer id; // 学号
private String name; // 姓名
private Integer age; // 年龄
private Banji banji; // 所属班级
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
//get,set方法在此省略,必须要写的
}
- 班级实体类
package cc.wenshixin.entity;
import java.util.HashSet;
import java.util.Set;
public class Banji {
private Integer id; //编号
private String name; //名称
private Set setStudent = new HashSet(); //班级里的学生
public Banji() {
}
public Banji(String name) {
this.name = name;
}
//get,set方法在此省略,必须要写的
}
- 工具类
package cc.wenshixin.utility;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtility {
private static Configuration cfg = null;
private static SessionFactory sessionFactory = null;
static{
cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
}
//获得sessionFactory对象的方法
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
2.2 映射文件
- 学生实体类映射文件
- 班级实体类映射文件
- 核心配置文件
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8
用户名
密码
true
true
update
org.hibernate.dialect.MySQL5InnoDBDialect
2.3 数据初始化
@Test
//初始化数据
public void initData()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//插入数据
Banji banji1 = new Banji("计科一班");
Banji banji2 = new Banji("计科二班");
Banji banji3 = new Banji("计科三班");
Banji banji4 = new Banji("计科四班");
Student student1 = new Student("小明", 20);
Student student2 = new Student("小红", 19);
Student student3 = new Student("小智", 21);
Student student4 = new Student("小张", 20);
Student student5 = new Student("小李", 19);
Student student6 = new Student("老王", 23);
Student student7 = new Student("小魏", 20);
banji1.getSetStudent().add(student1);
banji1.getSetStudent().add(student3);
banji2.getSetStudent().add(student2);
banji2.getSetStudent().add(student5);
banji2.getSetStudent().add(student4);
banji3.getSetStudent().add(student6);
banji4.getSetStudent().add(student7);
session.save(banji1);
session.save(banji2);
session.save(banji3);
session.save(banji4);
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
2.4 对象导航查询测试
@Test
//对象导航查询方式
public void test()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Banji banji = session.get(Banji.class, 2);
Set setStudent = banji.getSetStudent();
System.out.println(setStudent.size());
for (Student student : setStudent) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3.HQL 查询
常用的 hql 语句(关键字大小写都可以的):
-
- 查询所有:
from 实体类名称
- 查询所有:
-
- 条件查询(使用 AS 关键词设置别名):
from 实体类名称 as 别名 where 别名.属性名称=?
from 实体类名称 as 别名 where 别名.属性名称=? and 别名.属性名称=?
from 实体类名称 as 别名 where 别名.属性名称 like ?
- 条件查询(使用 AS 关键词设置别名):
-
- 排序查询:
from 实体类名称 as 别名 order by 别名.属性名称 asc/desc
- 排序查询:
-
- 分页查询:
通过调用方法来实现,设置开始位置query.setFirstResult(0);
,设置每页记录数query.setMaxResults(3);
- 分页查询:
5.投影查询:
在投影查询中才会用到SELECT
关键字,在前面的查询中是用不到的,并且不能使用 * 号。
select 属性名称 from 实体类名称6.函数查询:
在HQL中也是可以使用 sql 函数的,count()函数计算数量,sum()函数求和,avg()函数计算平均值,max()函数计算最大值,min()函数计算最小值。
hql语句查询步骤:
-
- 创建 Query 对象,写 hql 语句
-
- 调用 query 对象里面的方法得到结果
3.1 查询所有
@Test
//HQL查询表中所有数据
public void testQueryAll()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("FROM Banji");
List list = query.list();
for(Banji banji:list)
{
System.out.println(banji.getId()+":"+banji.getName());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3.2 条件查询
@Test
//HQL带条件的查询
public void testQueryWhere1()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("FROM Banji AS banji WHERE banji.id=?");
query.setParameter(0, 2);
List list = query.list();
for(Banji banji:list)
{
System.out.println(banji.getId()+":"+banji.getName());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
//模糊条件查询
public void testQueryWhere2()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("FROM Banji AS banji WHERE banji.name LIKE ?");
query.setParameter(0, "%计科%");
List list = query.list();
for(Banji banji:list)
{
System.out.println(banji.getId()+":"+banji.getName());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3.3 排序查询
@Test
//排序查询
public void testQueryOrder()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("FROM Banji AS banji ORDER BY banji.id DESC");
List list = query.list();
for(Banji banji:list)
{
System.out.println(banji.getId()+":"+banji.getName());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3.4 分页查询
@Test
//分页查询
public void testQueryPage()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("FROM Student");
query.setFirstResult(2);
query.setMaxResults(3);
List list = query.list();
for(Student student : list)
{
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3.5 投影查询
听起来很高大上,其实就是查询数据表中的某一列。。。
@Test
//投影查询
public void testQueryShade()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//注意返回的结果是一个object类型,而不是一个实体类的类型
Query
3.6 函数查询
需要类型转换
@Test
//函数查询
public void testQueryFunction()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("SELECT COUNT(id) FROM Student");
Object object = query.uniqueResult(); //获取查询结果唯一值
//先转换为long类型,再转换成int类型
Long obj = (Long)object;
int count = obj.intValue();
System.out.println(count);
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.QBC 查询
QBC 查询是通过 Restrictions 类的静态方法来实现的,具体的方法如下表所示。
静态方法 | 说明 |
---|---|
Restrictions.eq() | 等于 |
Restrictions.allEq() | 使用 Map,使用 key/value 进行多个等于的比较 |
Restrictions.gt() | 大于 > |
Restrictions.ge() | 大于等于 >= |
Restrictions.lt() | 小于 < |
Restrictions.le() | 小于等于 <= |
Restrictions.between() | 对应 sql 语句中的 between 语句 |
Restrictions.like() | 对应 sql 的like 语句 |
Restrictions.in() | 对应 sql 的 in 语句 |
Restrictions.and() | and 关系 |
Restrictions.or() | or 关系 |
Restrictions.sqlRestriction() | sql 限定查询 |
4.1 查询所有
@Test
public void testAll()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//查询所有
Criteria criteria = session.createCriteria(Student.class);
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.2 条件查询
@Test
public void testWhere1()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//条件查询
Criteria criteria = session.createCriteria(Student.class);
criteria.add(Restrictions.eq("id", 4)); //相当于where sid = 4
criteria.add(Restrictions.eq("age", 19));
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
public void testWhere2()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//模糊查询
Criteria criteria = session.createCriteria(Student.class);
criteria.add(Restrictions.like("name", "%小%"));
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.3 排序查询
@Test
public void testOrder()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//排序查询
Criteria criteria = session.createCriteria(Student.class);
criteria.addOrder(Order.desc("id"));
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.4 分页查询
话不多说,请看代码。
@Test
public void testPage()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//分页查询
Criteria criteria = session.createCriteria(Student.class);
criteria.setFirstResult(1);
criteria.setMaxResults(4);
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.5 函数查询
同 HQL 一样,QBC 也有函数查询,通过 Projections 类中的静态方法实现。
@Test
public void testFunction()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//函数查询
Criteria criteria = session.createCriteria(Student.class);
criteria.setProjection(Projections.rowCount());
List list = criteria.list();
Object obj = criteria.uniqueResult();
Long lobj = (Long)obj;
int count = lobj.intValue();
System.out.println(count);
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
4.6 离线查询
DetachedCriteria 翻译为离线条件查询,他不不依赖 Session 来创建,所以 DetachedCriteria 可以被其他层使用条件封装,在交给 DAO 层查询,在 SSH 框架的整合上经常使用。
@Test
public void testOutLine()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//离线查询
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Student.class);
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List list = criteria.list();
for (Student student : list) {
System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
}
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
5.hibernate 检索策略
5.1 多表连接查询。
在做表的查询时,有时要采用连接查询进行对表联合查询,下面是 mysql 中的多表查询写法。
交叉查询
查询的结果是返回被连接的表中的所有数据行的笛卡尔积,返回的结果条数也就是一个表的数据记录乘以另一个比表的数据记录数,在开发中最好不要使用交叉查询,因为数据量不算很大时,查询效率就极低,在设计数据表时应该避免这种查询方式。
select * from student, banji;内连接
select * from student, banji where student.sid=banji.bid;
select * from student inner join banji on student.sid=banji.bid;-
外连接
- 左外连接
select * from student left outer join banji on student.sid=banji.bid; - 右外连接
select * from student right outer join banji on student.sid=banji.bid;
- 左外连接
5.2 HQL 连接查询
5.2.1 内连接查询
内连接有一般的内连接查询,还有迫切内连接查询,迫切连接查询比一般的内连接查询多了一个 fetch
关键字两种方式返回的结果集不同。
@Test
//内连接查询
public void testQueryInner()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from Banji as b inner join b.setStudent");
List list = query.list(); //返回的是一个二维对象数组,list的每部分包含两个表中的数据
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
//迫切内连接查询
public void testQueryInnerFecth()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from Banji as b inner join fetch b.setStudent");
List list = query.list(); //返回的是一个一维对象数组,只包含联合表student中的数据
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
5.2.2 外连接
外连接也分一般的外连接查询和迫切外连接查询,并且还有左外连接和右外连接之分。
@Test
//迫切外连接查询
public void testQueryOuterFecth()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from Banji as b left outer join fetch b.setStudent");
List list = query.list(); //返回的是一个一维对象数组,只包含联合表student中的数据
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
//外连接查询
public void testQueryOuter()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from Banji as b left outer join b.setStudent");
List list = query.list(); //返回的是一个二维对象数组,包含两个表中的数据
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
5.3 HQL 检索(抓取)策略
hibernate 的检索策略也是提升性能的一种方式,可以在获取关联对象的时候,对发送的语句进行优化,但是抓取策略需要和延迟加载一起使用来提升性能。
在前面,使用的是 session 对象的 get() 方法来发送语句查询数据库,但还可以 load() 来做查询,两者的区别是:get() 方法会马上发送语句查询数据库,而 load() 方法只有在执行到使用查询对象语句时才会发送语句查询数据库,load的延迟方式就是延迟查询方式。
延迟查询分为两类:
-
- 类级别延迟:根据 id 查询返回实体类对象,调用 load 方法不会马上发送语句。
-
- 关联级别延迟:查询一个班级,再查询一个班级的所有学生是否需要延迟,这个过程就称为关联级别延迟。
延迟就是发送 sql 语句的时间是否是随写随发的,还是用到的数据值的时候再发。
关于类级别延迟就是方法的区别,而关联级别延迟需要在映射文件中进行配置,根据班级来得到所有学生,就需要在班级实体类的映射文件中配置。在 set
标签上使用fetch
属性和 lazy
属性。fetch
的默认就是 select 值,如果 fetch
属性的值为 join
那么 lazy
里面的值设置就失效了。设置 lazy
的值:true:表示延迟(默认);false:表示不延迟;extra表示极其延迟。
下面是示例代码:
类级别延迟
@Test
//get查询方式
public void testGet()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Banji banji = session.get(Banji.class, 2);
//这一句就发送sql语句
Set setStudent = banji.getSetStudent();
//这一句要打印的值只有在事务提交成功后才会显示
System.out.println(setStudent.size());
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
//load查询方式
public void testLoad()
{
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtility.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Banji banji = session.load(Banji.class, 2);
//这一句没有发送sql语句
Set setStudent = banji.getSetStudent();
//这一句才发送了sql语句,在事务提交后显示需要打印的值
System.out.println(setStudent.size());
tx.commit();
}catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
关联级别延迟
在班级实体类的配置文件中增加如下配置:
批量抓取配置
为了进一步的提高查询的效率,hibernate 还有批量抓取的配置,只需要在set文件中加上 batch-size 的属性,在里面写上数字,数字越大,查询时发送的语句就越少,最大一般写 10。