hibernate的查询方式
hibernate提供了5种查询方式,我们最主要的是用到HQL检索和QBC检索
OID检索
通过id来检索数据
使用get方法
Customer customer = session.get(Customer.class,1L);
使用load方法
Customer customer = session.get(Customer.class,1L);
对象导航检索
对象导航检索:hibernate根据一个已经查询到的对象,获取其关联的对象的一种查询方法(即通过获取到的对象,利用其实体类中关联的对象属性,获取其关联的对象)
根据获取到的联系人对象获取客户对象
LinkMan linkMan = session.get(LinkMan.class,1L);
Customer customer = linkMan.getCustrmer();
根据获取到的客户对象,获取其所有联系人对象的集合
Customer customer = session.get(Customer.class,1L);
Set<LinkMan> linkMans = customer.getLinkMans();
HQL检索
HQL查询:(hibernate query language),hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL,通过session.createQuery()(用于接收一个HQL语句的查询语句)
初始化数据
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 创建一个客户
Customer customer = new Customer();
customer.setCust_name("李向文");
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("王东" + i);
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer);
tx.commit();
}
HQL简单查询
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 简单的查询
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
// sql中支持*号的写法:select * from cst_customer; 但是在HQL中不支持*号的写法。
/*
* Query query = session.createQuery("select * from Customer");// 报错
* List<Customer> list = query.list();
*/
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
别名查询
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 别名的查询
/*
* Query query = session.createQuery("from Customer c"); List<Customer>
* list = query.list();
*/
Query query = session.createQuery("select c from Customer c");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
排序查询
/**
* 排序查询
*/
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序的查询
// 默认情况
// List<Customer> list = session.createQuery("from Customer order by
// cust_id").list();
// 设置降序排序 升序使用asc 降序使用desc
List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
条件查询
public void demo5() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 条件的查询
// 一、按位置绑定:根据参数的位置进行绑定。
// 一个条件
/*
* Query query = session.createQuery("from Customer where cust_name = ?"
* ); query.setParameter(0, "李兵"); List<Customer> list = query.list();
*/
// 多个条件
/*
* Query query = session.createQuery(
* "from Customer where cust_source = ? and cust_name like ?");
* query.setParameter(0, "小广告"); query.setParameter(1, "李%");
* List<Customer> list = query.list();
*/
// 二、按名称绑定
Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
// 设置参数:
query.setParameter("aaa", "朋友推荐");
query.setParameter("bbb", "李%");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
投影查询
public void demo6() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 投影查询
// 单个属性
/*
* List<Object> list = session.createQuery(
* "select c.cust_name from Customer c").list(); for (Object object :
* list) { System.out.println(object); }
*/
// 多个属性:
/*
* List<Object[]> list = session.createQuery(
* "select c.cust_name,c.cust_source from Customer c").list(); for
* (Object[] objects : list) {
* System.out.println(Arrays.toString(objects)); }
*/
// 查询多个属性,但是我想封装到对象中。需要在实体类中添加相应构造方法
List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
分页查询
public void demo7() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分页查询
Query query = session.createQuery("from LinkMan");
query.setFirstResult(20);
query.setMaxResults(10);
List<LinkMan> list = query.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
tx.commit();
}
分组统计查询
public void demo8() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 聚合函数的使用:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
// 分组统计:
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source")
.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tx.commit();
}
多表查询
SQL的多表查询
连接查询
交叉连接:笛卡尔积
select * from A,B;
内连接 :inner join (inner 可以省略)
隐式内连接:
select * from A,B where A.id = B.aid;
显示内连接:
select * from A inner join B on A.id = B.aid;
外连接 :
左外连接:left outer join(outer 可以省略)
select * from A left outer join B on A.id= B.aid;
右外连接:right outer join(outer 可以省略)
select * from A right outer join B on A.id = B.aid;
子查询
HQL的多表查询
连接查询
交叉连接
内连接:普通内连接,得到的是一个一个的Object[]对象,即List<Object[]>,将Customer对象和LinkMan对象分开来
迫切内连接,得到的是一个一个的Customer对象,即List<Customer>,将LinkMan对象封装到了Customer对象的List<LinkMan>中
迫切内连接
隐式内连接
显示内连接
外连接:外连接与内连接一样一样的
迫切左外连接
右外连接
左外连接
public void demo9() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// SQL:SELECT * FROM cst_customer c INNER JOIN cst_linkman l ON
// c.cust_id = l.lkm_cust_id;
// HQL:内连接 from Customer c inner join c.linkMans
/*
* List<Object[]> list = session.createQuery(
* "from Customer c inner join c.linkMans").list(); for (Object[]
* objects : list) { System.out.println(Arrays.toString(objects)); }
*/
// HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner
// join fetch c.linkMans
List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans")
.list();// 通知hibernate,将另一个对象的数据封装到该对象中
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
运行结果 所有的LinkMan对象都封装在了其customer中
QBC检索
QBC查询(query by criteria)条件查询,更加面向对象的查询方式
简单的查询
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 获得Criteria的对象
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
排序查询
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序查询
Criteria criteria = session.createCriteria(Customer.class);
// criteria.addOrder(Order.asc("cust_id")); // 升序
criteria.addOrder(Order.desc("cust_id")); // 降序
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
分页查询
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分页查询
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(10);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
tx.commit();
}
条件查询
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 条件查询
Criteria criteria = session.createCriteria(Customer.class);
// 设置条件:
/**
* = eq
* > gt
* >= ge
* < lt
* <= le
* <> ne
* like
* in
* and
* or
*/
criteria.add(Restrictions.eq("cust_source", "小广告"));
// criteria.add(Restrictions.or(Restrictions.like("cust_name", "李%")));
criteria.add(Restrictions.like("cust_name", "李%"));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
统计查询
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
/**
* add :普通的条件。where后面条件
* addOrder :排序
* setProjection :聚合函数 和 group by having
*/
criteria.setProjection(Projections.rowCount());
Long num = (Long) criteria.uniqueResult();
System.out.println(num);
tx.commit();
}
离线条件查询(DetachedCriteria)
适合查询带条件还带分页的查询,比如查询某一类的商品,并要求分页(SSH整合是经常要用到的查询方法)更适合多条件联合查询
public void demo6(){
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.like("cust_name", "李%"));
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
SQL检索
通过SQL语句进行查询
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
/*SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}*/
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
sqlQuery.addEntity(Customer.class);
List<Customer> list = sqlQuery.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
hibernate的抓取策略
hibernate的效率有可能是比较低的,因此hibernate中我们需要学习抓取策略
抓取策略:查询关联对象的优化
hibernate的效率不是特别高,因此hibernate提供了几种优化手段,如hibernate的缓存机制,hibernate的抓取策略
抓取策略一般不单独用,一般与延迟加载一起使用
延迟加载的概述
延迟加载:lazy(懒加载)执行到该行代码时,不会发送语句去进行查询,而在真正使用这个对象的属性是才会发送SQL语句进行查询
延迟加载的分类
类级别的延迟加载
指的是通过load方法查询某个类对象时,是否采用延迟 session.load(Customer.class,1L);
类级别延迟加载通过在类的映射文件中的<class>标签的lazy属性进行配置,默认lazy=“true”表示采用延迟加载,所以我们采用load方法去获取类对象时会延迟加载
<class name="com.itheima.hibernate.domain.Customer" lazy="true">
如何让lazy失效:
将lazy设置成false
将持久化类使用final修饰
Hibernate.Initialize();//相当于将类对象初始化,使用一下类对象
/**
* 类级别的延迟加载
* * 在<class>的标签上配置的lazy
*/
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = session.load(Customer.class, 1l);
Hibernate.initialize(customer);
System.out.println(customer);
tx.commit();
}
再讲lazy改为false
关联级别的延迟加载
指的是在查询某个对象时,查询其关联对象时,是否采用延迟
Customer customer = session.get(Customer.class,1L);
customer.getLinkMans(); 通过客户获得联系人时,联系人对象是否采用了延迟
需要在<set><many-to-one>这些标签中设置lazy
抓取策略一般与关联级别的延迟加载一起使用,以达到优化SQL语句的作用
抓取策略
抓取策略的概述
通过一个对象可以抓取到其关联对象,需要发送SQL语句的,但是这些语句发送成什么样的格式,需要通过策略进行配置
通过在<set>或<many-to-one>上通过fetch属性进行设置
通过设置fetch(有很多的值)和这些标签上的lazy(也有很多值)的值配合使用,来优化发送的SQL语句
(前面的 迫切内连接 也用到了fetch)
<set>上的fetch和lazy
fetch 抓取策略:控制SQL语句格式
select :默认值,发送普通的SQL语句 查询其关联对象
join :发送一条迫切左外连接查询关联对象
subselect :发送一条子查询查询其关联对象
lazy 延迟加载:控制查询关联对象的时候是否采用延迟
true :默认值,查询关联对象的时候,采用延迟加载
false :查询关联对象的时候,不采用延迟加载
extra :极其懒惰,用什么样的语句就发什么样的语句,不会多发一点点
默认情况,即fetch = "select" lazy = "true"
/**
* 默认情况:
*/
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询客户的SQL
System.out.println(customer.getCust_name());
// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
System.out.println(linkMan.getLkm_name());
}
tx.commit();
}
配置set标签的 fetch = "select" lazy = "false"
/**
* 设置 fetch="select" lazy="false"
*/
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 3l);
// 发送两条SQL语句:查询客户的名称,查询客户关联联系人
System.out.println(customer.getCust_name());
/*// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) {//
System.out.println(linkMan.getLkm_name());
}*/
System.out.println(customer.getLinkMans().size());
tx.commit();
}
打印结果
配置set标签的 fetch = "select" lazy = "extra"
/**
* 设置fetch="select" lazy="extra"
*/
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询1号客户的SQL语句
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 发送一条select count() from ...;
tx.commit();
}
配置set标签的 fetch = "join" lazy = "true"
fetch = "join"表示将使用迫切左外连接查询数据库,会将当前对象和其关联对象一起一次性查出,而lazy控制的是延迟加载,在这种情况下相当于失效了
* 设置fetch="join" lazy=失效
*/
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 3l);// 发送一条迫切左外连接查询记录
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 不发送
tx.commit();
}
配置set标签的 fetch = "subselect" lazy = "true"
子查询 必须要查询多个对象才行 如果不查询多个,hibernate会直接将子查询 in语句 变成 = (对于只查询一个对象 = 符号肯定比 in语句 效率更高) 从而无法体现子查询
配置set标签的 fetch = "subselect" lazy = "false"
/**
* 设置fetch="subselect" lazy="false"
*/
public void demo7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();
/*发送查询所有客户的SQL,发送一条子查询,延迟失效,
hibernate会在这里直接将当前查询的类对象及其关联类对象全部查出*/
for (Customer customer : list) {
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());//
}
tx.commit();
}
在我们开发过程中,一般将fetch和lazy设置成默认的
<many-to-one>这类标签上的fetch和lazy
fetch:抓取策略,控制SQL语句的格式
select 默认值,发送普通的SQL语句
join 发送一条迫切左外连接
lazy :延迟加载,控制查询关联对象是否采用延迟
proxy 默认值,proxy具体的取值,取决于另一端的<class>上的lazy值
false 不采用延迟
no-proxy (不会使用)
在我们开发过程中,一般将fetch和lazy设置成默认的
批量抓取
/**
* 获取客户的时候,批量抓取联系人
* 在Customer.hbm.xml中set上配置batch-size
*/
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println(customer.getCust_name());
for (LinkMan linkMan : customer.getLinkMans()) {
System.out.println(linkMan.getLkm_name());
}
}
tx.commit();
}
/**
* 获取联系人的时候,批量抓取客户
* * 在Customer.hbm.xml中<class>上配置
*/
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<LinkMan> list = session.createQuery("from LinkMan").list();
for (LinkMan linkMan : list) {
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());
}
tx.commit();
}