Hibernate入门(四)—— 查询

2018-02-13 by gdwkong

一、Hibernate查询

1.Hibernate检索(查询)方式的分类

OID检索 :根据主键查询,get/load

对象导航检索 :通过一个对象获得其关联对象.【重点】

Category category = session.get(Category.class, 1);
Set<Product> products = category.getProducts();

HQL检索 :HQL,Hibernate Query Language(Hibernate查询语言,语法与SQL类似,但是又是面向对象的 ) 【掌握】

QBC检索 :QBC,Query By Criteria(条件查询,更加面向对象的查询方式) 【掌握】

SQL检索 :SQL,使用原生SQL进行查询 【了解】

2.HQL查询

2.1概述

​   HQL:Hibernate Query Language。 是面向对象(在sql里面的列名在hql里面应该写属性名)的查询语言, 它和SQL查询语言有些相似。

​ 语法: 

String hql =...

​ Query query = session.createQuery(hql);

list(); 查询多个

uniqueResult();查询一个

​原则: 把表名改成类名, 把数据库的列改成Java里面的属性名

2.2基本查询
2.2.1查询所有

查询所有的分类

1 //查询所有的分类 2 @Test 3 public void fun01(){ 4 Session session = HibernateUtils.openSession(); 5 Transaction transaction = session.beginTransaction(); 6 7 //String hql = "select c from Category c"; 8 String hql = "from Category"; 9 Query query = session.createQuery(hql);10 List<Category> list = query.list();11 for (Category category : list) {12 System.out.println(category.toString());13 }14 15 transaction.commit();16 session.close();17 }
2.2.2条件查询

大于,小于,大于等于,大于小于查询

1 //查询id大于1的分类 2 @Test 3 public void fun02(){ 4 Session session = HibernateUtils.openSession(); 5 Transaction transaction = session.beginTransaction(); 6 7 /*String hql = "from Category where cid > ?"; 8 Query query = session.createQuery(hql); 9 query.setInteger(0, 1);*/10 11 String hql = "from Category where cid > :类别id";12 Query query = session.createQuery(hql);13 query.setInteger("类别id", 1);14 List<Category> list = query.list();15 for (Category category : list) {16 System.out.println(category.toString());17 }18 19 transaction.commit();20 session.close();21 }

like查询

1 //查询商品名包含iPhone的商品 2 @Test 3 public void fun03(){ 4 Session session = HibernateUtils.openSession(); 5 Transaction transaction = session.beginTransaction(); 6 7 8 String hql = "from Product where pname like ?"; 9 Query query = session.createQuery(hql);10 query.setString(0, "%iPhone%");11 List<Product> list = query.list();12 for (Product product: list) {13 System.out.println(product.toString());14 }15 16 transaction.commit();17 session.close();18 }

between and查询

String hql = "from Product where price between ? and ?";Query query = session.createQuery(hql);query.setDouble(0, 2000);query.setDouble(1, 5000);List<Product> list = query.list();

in 查询

1 @Test 2 //查询pid在(2,8,11,12,100)的商品信息 3 public void fun05(){ 4 Session session = HibernateUtils.getCurrentSession(); 5 Transaction transaction = session.beginTransaction(); 6 7 //String sql = "select * from t_product where pid in(?,?,?,?)"; 8 String hql = "from Product where pid in(?,?,?,?)"; 9 Query query = session.createQuery(hql);10 //设置参数,查询11 List list = query.setInteger(0, 2).setInteger(1, 8).setInteger(2, 11).setInteger(3, 12).list();12 13 System.out.println(list.toString());14 15 transaction.commit();16 ​17 }
2.3.聚合查询

统计类别的个数

String hql = "select count(*) from Category";Query query = session.createQuery(hql);Long n = (Long) query.uniqueResult();System.out.println(n.intValue());
2.4分组查询

统计各个类别的商品数量

String hql = "select category.cid, count(*) from Product group by category.cid";Query query = session.createQuery(hql);List<Object[]> list = query.list();for (Object[] objects : list) { System.out.println(Arrays.toString(objects));}
2.5排序查询

安照商品价格(升序)查询所有的商品

String hql = "from Product order by price asc";Query query = session.createQuery(hql);List<Product> list = query.list();for (Product product : list) { System.out.println(product);}
2.6.分页查询

​ setFirstResult:设置开始查询的下标,最小取值是0,0代表第一条记录

​ setMaxResults: 设置查询结果显示的条数。

显示第一页的数据,一页显示4条

String hql = "from Product";Query query = session.createQuery(hql);query.setFirstResult(0);query.setMaxResults(4);List<Product> list = query.list();for (Product product : list) { System.out.println(product);}
2.7 投影查询

​ 查询指定字段

查询商品的名字和价格

String hql = "select pname, price from Product";Query query = session.createQuery(hql);List<Object[]> list = query.list();for (Object[] objects : list) { System.out.println(Arrays.toString(objects));}

3.QBC查询

3.1概述

​   QBC,Query By Criteria(条件查询,更加面向对象的查询方式)

3.2常见的条件查询

语法

//创建QBC条件查询Criteria criteria = session.createCriteria(Class);//添加条件criteria.add(Restrictions.api...);//查询多个List list = criteria.list();//或者查询一个Object object = criteria.uniqueResult();
运算符条件API描述
=Restrictions.eq()等于
>Restrictions.gt()大于
<Restrictions.lt()小于
>=Restrictions.ge()大于等于
<=Restrictions.le()小于等于
betweenRestrictions.between()在某个范围内
likeRestrictions.like()模糊查询
inRestrictions.in()在...中
andRestrictions.and()并且
orRestrictions.or()或者

Java代码

1 // 条件查询 2 @Test 3 public void fun01() { 4 Session session = HibernateUtils.openSession(); 5 Transaction transaction = session.beginTransaction(); 6 ​ 7 Criteria criteria = session.createCriteria(Product.class); 8 List<Product> list = criteria.add(Restrictions.between("price", 2000.0, 3000.0)).list(); 9 for (Product product : list) {10 System.out.println(product.toString());11 }12 13 transaction.commit();14 session.close();15 }//and 查询; 查询商品名以iP开头的并且价格大于4000的商品Criteria criteria = session.createCriteria(Product.class);List<Product> list = criteria.add(Restrictions.like("pname", "iP%")).add(Restrictions.gt("price", 4000.0)).list();
//or查询; 查询价格大于3000的或者pid=1的商品Criteria criteria = session.createCriteria(Product.class);List<Product> list = criteria.add(Restrictions.or(Restrictions.gt("price", 3000.0)).add(Restrictions.eq("pid", 1))).list();
3.3.聚合查询

语法

//创建QBC条件查询Criteria criteria = session.createCriteria(Class);//设置聚合criteria.setProjection(Projections.api...);//查询出结果long result = (long) criteria.uniqueResult();
运算符条件API描述
sumProjections.sum()求和
countProjections.count()计数
maxProjections.max()最大值
minProjections.min()最小值
avgProjections.avg()平均值

统计商品的数量

Criteria criteria = session.createCriteria(Product.class);Object result = criteria.setProjection(Projections.count("pid")).uniqueResult();System.out.println("result="+result);

多项聚合

//创建QBC条件查询Criteria criteria = session.createCriteria(Class);//添加多种聚合ProjectionList list = Projections.projectionList();list.add(Projections.api...);...//设置聚合criteria.setProjection(list);//查询出结果Object[] result = (Object[]) criteria.uniqueResult();//实例//统计每一个类别下的商品数量 cid count(pid) 两个聚合条件Criteria criteria = session.createCriteria(Product.class);ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("category.cid"));projectionList.add(Projections.count("pid"));List<Object[] > list = criteria.setProjection(projectionList).list();
3.4分组查询

统计不同类别下商品的数量

Criteria criteria = session.createCriteria(Product.class);ProjectionList projectionList = Projections.projectionList();projectionList.add(Projections.count("pid")).add(Projections.groupProperty("category.cid"));​List<Object[]> list = criteria.setProjection(projectionList).list();for (Object[] objects : list) { System.out.println(Arrays.toString(objects));}
3.5排序查询

语法

//创建QBC条件查询Criteria criteria = session.createCriteria(Class);//添加排序criteria.addOrder(Order.api...);//查询出结果List list = criteria.list();
运算符条件API描述
descOrder.desc()降序
ascOrder.asc()升序
3.6.分页查询

​ setFirstResult:设置开始查询的下标,最小取值是0,0代表第一条记录 设置a

​ setMaxResults: 设置查询结果显示的条数。 设置 b

3.7离线条件查询

​   我们之前也执行过条件查询,不过这些条件查询都是先创建了Criteria对象,然后再不断的追加条件。这种情况在提交比较少的时候,看上去是还不错的。 假如我们这些参数都是要上层service 传递过来的,那么显得就不是那么好看了。所以我们想想能否在外面先封装好了,然后直接给我一个总的条件即可。 这个总的条件,就是包含了前面的所有的条件。这就是离线条件查询。 意思是,可以现在前面先封装条件, 脱离session 创建出Criteria这个情况。

语法

//创建离线的DetachedCriteria对象DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);//设置条件detachedCriteria.add(Restrictions.like("u_name", "%奥%"));//转成可执行状态Criteria criteria = detachedCriteria.getExecutableCriteria(session);List<User> list = criteria.list();

4,SQL查询【了解】

Eg

String sql = "select * from t_product";SQLQuery sqlQuery = session.createSQLQuery(sql);sqlQuery.addEntity(Product.class);​List<Product> list = sqlQuery.list(); for (Product product : list) { System.out.println(product.toString());}

5.连接查询

5.1MySql里面的多表查询
5.1.1交叉查询

语法

select * from A,B
5.1.2内连接查询

隐式内连接查询

select * from A ,B where A.id = B.id;

显示内连接

select * from A inner join B on A.id = B.id;
5.1.3外连接查询

左外连接

select * from A left outer join B on A.id = B.id;

右外连接

select * from A right outer join B on A.id = B.id;
5.2 HQL连接查询
5.2.1类别

交叉连接

内连接:内连接、迫切内连接

外连接:​左外连接、右外连接

连接类型语法
内连接inner join 或者 join
迫切内连接inner join fetch 或者 join fetch
左外连接left outer join 或者 left join
迫切左外连接left outer join fetch 或者 left join fetch
右外连接right outer join 或者 right join
迫切右外连接right outer join fetch 或者 right join fetch
5.2.2内连接

​ 内连接查询可以获取两表的公共部分的记录。

HQL内连接(发送三条查询语句)

String hql = "from Category c inner join c.products";Query query = session.createQuery(hql);List<Object[]> list = query.list();

HQL迫切内连接(发送一条查询语句)

//String hql = "from Category c inner join fetch c.products";String hql = "select distinct c from Category c inner join fetch c.products";Query query = session.createQuery(hql);List<Category> list = query.list();
5.2.3外连接

HQL左外连接

String hql = "from Category c left outer join c.products";List<Object[]> list = session.createQuery(hql).list();

HQL迫切左外连接

String hql = "from Category c left outer join fetch c.products";List<Category> list = session.createQuery(hql).list();

  总结:

​ 迫切连接是Hibernate独有的查询方式,迫切内连接比内连接多一个关键字fetch​ 内连接查询结果中为Object[]数组​ 迫切内连接查询结果为具体对象。

二、查询优化

1、类级别延迟加载

1.1 描述

​ 懒加载默认是开启的.一般不需要修改

​ session.get(): 非懒加载方法

​ session.load(): 默认就是是懒加载

1.2使load懒加载失效

​  在映射配置文件的<class>标签上配置lazy=”false” 

<class name="com.pri.bean.Category" table="t_category" lazy="false">

2.关联级别的懒加载

2.1 概述

​   当查询对应的对象时候, 是否立即查询出其关联的对象; eg: 查询id的为1分类,是否立即查询出是该类别下的商品

​   一般通过 '抓取策略' 和 '懒加载' 配合起来优化查询.抓取策略:意思是抓取其关联对象,在<set>和<many-to-one>标签上有一个fetch属性,fetch控制发送什么类型的语句来抓取其关联的对象

​   fetch: 抓取策略 :控制发送什么类型的Sql语句 sql语句:就是对表查询(连接)

​   lazy: 懒或者不懒

2.2set的懒加载
2.2.1描述

在一的一方操作,即在set标签上配置 fetch 和 lazy

fetch:控制的是查询其关联对象的时候采用的SQL语句的格式.

fetch的取值发送的SQL语句类型
select:默认值发送一条select语句查询其关联对象.
join发送一条迫切左外连接查询关联对象.
subselect发送一条子查询查询其关联对象.

lazy:控制的是查询其关联对象的时候是否采用延迟加载的策略.

lazy的取值含义
true(默认值)默认查询关联对象的时候采用延迟加载.
false查询关联对象的时候 不采用延迟加载
extra及其懒惰. 查询关联对象的时候 采用比延迟加载更懒惰的方式进行查询.
2.2.2例子

​ 下面的操作都是在在一的一方操作,即在set标签上配置 fetch 和 lazy

当fetch取值为select的时候

fetch的取值lazy的取值结果
selecttrue多方在使用时才进行加载(懒加载) 注: 默认值
selectfalse多方在一方加载时就加载(不是懒加载)
selectextra多方在使用时才进行加载,如果使用时的操作是聚合类型,那么只会进行聚合查询。

当fetch取值为join的时候

fetch的取值lazy的取值结果
joinlazy失效(不管是true还是false)fetch采用的是迫切左外连接查询,将两张表的结果全部查询出来。lazy失效。

当fetch取值为subselect的时候

fetch的取值lazy的取值结果
subselecttrue多方在使用时才进行加载,发送的是子查询语句
subselectfalse多方在一方加载时就加载,发送的是子查询语句
subselectextra多方在一方加载时就加载,如果使用时的操作是聚合类型,那么只会进行聚合查询发送的是子查询语句

注意: 使用Hibernate子查询时候,不能查一个. Hibernate如果发现in() 的值是一个,把in变成=

2.3many-to-one懒加载
2.3.1描述

在多的一方操作,即在many-to-one标签上配置 fetch 和 lazy

fetch:控制的是查询其关联对象的时候采用的SQL语句的格式.

fetch的取值发送的SQL语句类型
select:默认值发送一条select语句查询其关联对象.
join发送一条迫切左外连接查询关联对象.

lazy:查询其关联对象的时候是否采用延迟加载.

lazy的取值含义
proxy默认值.是否采用延迟 取决于 一的一方的class上的lazy的值.
false不采用延迟加载其关联对象.
no-proxy(了解)不用研究是否采用延迟
2.3.2例子

​ 下面的操作都是在多的一方操作,即在many-to-one标签上配置 fetch 和 lazy

当select为fetch的时候,发送的是普通的sql语句

fetch的取值lazy的取值结果
selectproxy如果一的一方的class上的lazy的值为true,使用一的一方再加载(懒加载); 如果一的一方的class上的lazy的值为false,一方在多方加载时就加载(不是懒加载)
selectfalse一方在多方加载时就加载(不是懒加载)

当select为join的时候,是迫切左外连接

fetch的取值lazy的取值结果
join失效发送左外连接查询,不是懒加载

3 批量抓取(了解)

在set标签上配置 batch-size = num

1 Criteria criteria = session.createCriteria(Category.class);2 List<Category> list = criteria.list();3 ​4 for (Category category : list) {5 Set<Product> products = category.getProducts();6 for (Product product : products) {7 System.out.println(product.toString());8 }9 }

同时抓取多方表中指定的条数的数据

最新更新:

第七城市

栏目导航(关闭)