一、 Hibernate查询高级
1. 查询总结
1.oid查询-get
2.对象属性导航查询
3.HQL
4.Criteria
5.原生SQL
2. 查询-HQL语法
1)基础语法
/** * 基本语法 */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql1 = "from com.java.domain.Customer"; //完整写法 String hql2 = "from Customer"; //简单写法 //2>创建查询的对象 Query query = session.createQuery(hql2); //3>执行查询操作 List<Customer> list = query.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
2)排序
/** * 排序查询 * */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql1 = "from Customer order by cust_id desc"; //降序查询 String hql2 = "from Customer order by cust_id asc"; //升序查询 //2>创建查询的对象 Query query = session.createQuery(hql2); //3>执行查询操作 List<Customer> list = query.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
3)条件查询
?占位符和命名占位符
/** * 条件查询 * ?占位符 * 命名占位符 */ @Test public void fun3() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql1 = "from Customer where cust_id=?"; //简单写法 String hql2 = "from Customer where cust_id=:cust_id"; //2>创建查询的对象 Query query = session.createQuery(hql2); //设置查询的参数 //query.setParameter(0, 1l); query.setParameter("cust_id", 1l); //3>执行查询操作 List<Customer> list = query.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
4)分页查询
limit ?,?
query.setFirstResult(2);
query.setMaxResults(2);
/** * 分页查询 * limit ?,? * query.setFirstResult(2); * query.setMaxResults(2); */ @Test public void fun4() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql = "from Customer"; //简单写法 //2>创建查询的对象 Query query = session.createQuery(hql); //limit ?,? query.setFirstResult(2); query.setMaxResults(2); //3>执行查询操作 List<Customer> list = query.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
5)统计检索(聚合函数)
/** * 统计检索(聚合函数) * */ @Test public void fun5() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql1 = "select count(*) from Customer"; //简单写法 String hql2 = "select sum(cust_id) from Customer"; //简单写法 String hql3 = "select avg(cust_id) from Customer"; //简单写法 String hql4 = "select min(cust_id) from Customer"; //简单写法 String hql5 = "select max(cust_id) from Customer"; //简单写法 //2>创建查询的对象 Query query = session.createQuery(hql5); //3>执行查询操作 Number result = (Number) query.uniqueResult(); System.out.println(result); //4. 提交事务并释放资源 tx.commit(); session.close(); }
6)投影查询
/** * 投影查询 * */ @Test public void fun6() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql1 = "select cust_id from Customer"; //简单写法 String hql2 = "select cust_id,cust_name from Customer"; //简单写法 String hql3 = "select new Customer(cust_id, cust_name) from Customer"; //简单写法 //2>创建查询的对象 Query query = session.createQuery(hql3); //3>执行查询操作 List list = query.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
7)多表查询
1) 原生SQL
交叉连接-笛卡尔积(避免)
select * from A,B
内连接
|-隐式内连接
select * from A,B where B.aid=A.aid
|-显式内连接
select * from A inner join B on B.aid=A.aid
外连接
|-左外连接
select * from A left [outer] B on B.aid=A.aid
|-右外连接
select * from A right [outer] B on B.aid=A.aid
2)HQL的多表查询
内连接(迫切)
外连接
|-左外(迫切)
|-右外(迫切)
3)HQL多表查询的案例
public class Demo02 { /** * 内连接 * 将连接两端的对象分别返回放入数组 */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql = "from Customer c inner join c.linkMens"; //完整写法 //2>创建查询的对象 Query query = session.createQuery(hql); //3>执行查询操作 List<String[]> list = query.list(); for(Object[] obj : list) { System.out.println(Arrays.toString(obj)); } //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 内连接迫切 * 将两端的对象封装成一个对象返回 * from Customer c inner join c.linkMens */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql = "from Customer c inner join fetch c.linkMens"; //完整写法 //2>创建查询的对象 Query query = session.createQuery(hql); //3>执行查询操作 List<Customer> list = query.list(); for(Customer c : list) { System.out.println(c); } //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 左外连接 * 将连接两端的对象分别返回并放到数组中 * from Customer c left join c.linkMens */ @Test public void fun3() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql = "from Customer c left join c.linkMens"; //完整写法 //2>创建查询的对象 Query query = session.createQuery(hql); //3>执行查询操作 List<Object[]> list = query.list(); for(Object[] obj : list) { System.out.println(Arrays.toString(obj)); } //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 右外连接 * 将连接两端的对象分别返回并放到数组中 * from Customer c right join c.linkMens */ @Test public void fun4() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>定义hql语句 String hql = "from Customer c right join c.linkMens"; //完整写法 //2>创建查询的对象 Query query = session.createQuery(hql); //3>执行查询操作 List<Object[]> list = query.list(); for(Object[] obj : list) { System.out.println(Arrays.toString(obj)); } //4. 提交事务并释放资源 tx.commit(); session.close(); } }
3. 查询-Criteria语法
1)基本知识
QBC(Query By Criteria)是hibernate提高的另一种检索对象的方式,它主要由Criteria接口Criterion接口和Expression类组成。Criteria接口是Hibernate API中的一个查询接口,它需由session进行创建。Criterion是Criteria的查询条件,在Criteria中提供了add(Criterion criterion)方法来添加查询条件。使用QBC检索对象的示例代码如下:
//1>创建ceriteria对象 Criteria criteria = session.createCriteria(Customer.class); //2>添加查询条件 //criteria.add(Restrictions.idEq(1l)); criteria.add(Restrictions.eq("cust_id", 1l)); //3>执行查询 List<Customer> list = criteria.list();
QBC检索是使用Restrictions对象编写查询条件的,在Restrictions类中提供了大量的静态方法来创建查询条件,其常用的方法如表所示:
2)基本查询
/** * 基本语法 */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>创建ceriteria对象 Criteria criteria = session.createCriteria(LinkMan.class); //2>执行查询 List<LinkMan> list = criteria.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
2)条件查询
/** * 条件查询 */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>创建ceriteria对象 Criteria criteria = session.createCriteria(Customer.class); //2>添加查询条件 //criteria.add(Restrictions.idEq(1l)); criteria.add(Restrictions.eq("cust_id", 1l)); //3>执行查询 List<Customer> list = criteria.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
3)分页查询
/** * 分页查询 * limit ?,? * criteria.setFirstResult(0); * criteria.setMaxResults(2); */ @Test public void fun3() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>创建ceriteria对象 Criteria criteria = session.createCriteria(Customer.class); //2>设置分页查询的参数 limit ?,? criteria.setFirstResult(0); criteria.setMaxResults(2); //3>执行查询 List<Customer> list = criteria.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
4)排序查询
/** * 排序查询 * criteria.addOrder(Order.asc("cust_id")); //升序查询 * criteria.addOrder(Order.desc("cust_id")); //降序查询 */ @Test public void fun4() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>创建ceriteria对象 Criteria criteria = session.createCriteria(Customer.class); //2>添加排序条件 //criteria.addOrder(Order.asc("cust_id")); //升序查询 criteria.addOrder(Order.desc("cust_id")); //降序查询 //3>执行查询 List<Customer> list = criteria.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
5)统计查询
/** * 统计查询 * 总记录数 * criteria.setProjection(Projections.rowCount()); */ @Test public void fun5() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 //1>创建ceriteria对象 Criteria criteria = session.createCriteria(Customer.class); //2>设置查询目标 总记录数 criteria.setProjection(Projections.rowCount()); //3>执行查询 List<Customer> list = criteria.list(); System.out.println(list); //4. 提交事务并释放资源 tx.commit(); session.close(); }
4. 查询优化
1)类级别查询
get方法:没有任何策略.调用即立即查询数据库加载数据.
load方法: 应用类级别的加载策略
懒加载 延迟加载
load()方法(默认):是在执行时,不会发送任何sql语句,通过动态代理返回一个对象,
在对象使用的时候,才执行查询
延迟加载:仅仅获得没有使用,不会查询。在使用时,才进行查询
是否对类延迟加载可以通过在class元素上配置lazy属性
lazy(默认):true 加载时不查询,使用时才查询
lazy:false load方法与get方法没有任何区别 加载时立即查询
为了提高效率建议使用懒加载
public class Demo { /** * get()方法:立即加载。执行方法时立即发送sql语句查询结果 */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.get(Customer.class, 2l); System.out.println(c); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * load()方法(默认):是在执行时,不会发送任何sql语句,通过动态代理返回一个对象, * 在对象使用的时候,才执行查询 * 延迟加载:仅仅获得没有使用,不会查询。在使用时,才进行查询 * 是否对类延迟加载可以通过在class元素上配置lazy属性 * lazy(默认):true 加载时不查询,使用时才查询 * lazy:false 加载时立即查询 */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.load(Customer.class, 2l); System.out.println(c); //4. 提交事务并释放资源 tx.commit(); session.close(); } }
2)关联级别查询
1. 集合策略
lazy属性:决定是否延迟加载
true(默认值):延迟加载,懒加载
false:立即加载
extra:及其懒惰
fetch属性:决定加载策略,使用什么类型的sql语句加载集合数据
select(默认值):单表查询加载
join:使用多表查询加载集合
subselect:使用子查询加载查询集合
/** * * 关联级别 延迟加载 * 集合级别的关联 * @author vanguard * */ public class Demo { /** * 集合级别的关联 * fetch:select 单表查询 * lazy:true 延迟加载 使用时才加载集合数据 */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.get(Customer.class, 2l); Set<LinkMan> linkMens = c.getLinkMens(); //关联级别 System.out.println(linkMens); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:select 单表查询 * lazy:false 立即加载数据 */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.get(Customer.class, 2l); Set<LinkMan> linkMens = c.getLinkMens(); //关联级别 System.out.println(linkMens); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:select 单表查询 * lazy:extra 极其懒惰 * 与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句) */ @Test public void fun3() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.get(Customer.class, 2l); Set<LinkMan> linkMens = c.getLinkMens(); //关联级别 System.out.println(linkMens.size()); System.out.println(linkMens); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:join 使用多表查询加载集合数据 * lazy:true|false|extra失效 立即加载 */ @Test public void fun4() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 Customer c = session.get(Customer.class, 2l); Set<LinkMan> linkMens = c.getLinkMens(); //关联级别 System.out.println(linkMens.size()); System.out.println(linkMens); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:subselect 使用子查询加载集合数据 * lazy:true 延迟加载 */ @Test public void fun5() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); for(Customer c : list) { System.out.println(c.getLinkMens()); } //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:subselect 使用子查询加载集合数据 * lazy:false 立即加载加载 */ @Test public void fun6() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); for(Customer c : list) { System.out.println(c.getLinkMens()); } //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * 集合级别的关联 * fetch:subselect 使用子查询加载集合数据 * lazy:extra 极其懒惰加载 */ @Test public void fun7() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); for(Customer c : list) { System.out.println(c.getLinkMens().size()); System.out.println(c.getLinkMens()); } //4. 提交事务并释放资源 tx.commit(); session.close(); } }
2. 关联属性策略
fetch属性 决定加载的sql语句
select:使用单表查询
join:使用多表查询
lazy:决定加载时机
false:立即加载
proxy:有customer的类级别加载策略决定
/** * * 关联级别 延迟加载 * 属性策略 * @author vanguard * */ public class Demo02 { /** * * fetch:select 单表查询 * lazy:proxy * Customer--true */ @Test public void fun1() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 LinkMan linkMan = session.get(LinkMan.class, 1l); Customer customer = linkMan.getCustomer(); System.out.println(customer); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * * fetch:select 单表查询 * lazy:proxy * Customer--false 立即加载 */ @Test public void fun2() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 LinkMan linkMan = session.get(LinkMan.class, 1l); Customer customer = linkMan.getCustomer(); System.out.println(customer); //4. 提交事务并释放资源 tx.commit(); session.close(); } /** * * fetch:join 多表查询 * lazy:proxy 失效 都是立即加载 */ @Test public void fun3() { //1. 获得session Session session = HibernateUtils.getSession(); //2. 开启事务并获得操作事务的对象 Transaction tx = session.beginTransaction(); //3. 执行操作 LinkMan linkMan = session.get(LinkMan.class, 1l); Customer customer = linkMan.getCustomer(); System.out.println(customer); //4. 提交事务并释放资源 tx.commit(); session.close(); } }
结论:为了提高效率.fetch的选择上应选择select. lazy的取值应选择 true. 全部使用默认值.
4. no-session问题解决:
扩大session的作用域
3)批量抓取
betch-size:值是抓取集合的数量
抓取客户的集合时,一次抓取集合客户的联系人