hibernate_day04

多表关联情况下,如果想在控制台输出对象,需要有一方的ToString方法放弃另一方,否则相当于死循环打印StackOverflowError
mysql封装count会自动封装为Long类型
Hibernate的查询方式
1.hibernate的五种查询方式
* OID检索:根据hibernate唯一标识来查询
 	session.get()/load();
		Customer customer = session.get(Customer.class,1L);
* 对象图导航检索: 根据已经查询出来的对象,找到它的关联对象数据
	session.get()/load();
        Customer customer = session.get(Customer.class,1L);
        LinkMan linkMan = customer.getLinkManSet().get(0);
* HQL检索:通过传入的HQL进行查询。
	HQL:Hibernate Query Language.语法与SQL类似。面向对象的查询方式。
* QBC检索:通过传入Criteria对象进行查询。
	QBC:Query By Criteria.更加面向对象的方式查询。
* SQL检索:通过SQL查询。
	SQL:通过SQL语句进行查询的方式。在hibernate中,通常复杂的查询语句才用SQL
HQL查询
1.查询全部
Query query = session.createQuery("from Customer");
List<Customer> customerList = query.list();

2.条件查询
* 根据索引对占位符赋值
Query query = session.createQuery("from Customer where name = ? and age = ? ");
query.setParameter(0,"张三");
query.setParameter(1,18);
* 根据自定义变量(":变量")对占位符赋值
Query query = session.createQuery("from Customer where name = :aaa and age = :bbb ");
query.setParameter("aaa","张三");
query.setParameter("bbb",18);	
List<Customer> customerList = query.list();

3.分组查询
group by 实体类属性
4.排序查询
order by 实体类属性 ASC/DESC
5.分页查询
query.setFirstResult("开始的索引");
query.setMaxResults("每页显示的条数");

6.投影查询:只查询对象的部分属性
Query query = session.createQuery("select c.name,c.age from Customer c");
* 默认每条结果封装为Object[]数组
List<Object[]> list = query.list();
* 配置将查询结果封装到实体类对象中
第一步:配置实体类,提供相应的带参构造方法(需要投影哪些属性,就提供带哪些参数的构造方法),最好再补一个空参
第二步,在HQL中new 对象
Query query = session.createQuery("select new Customer(c.name,c.age) from Customer c");
List<Customer> customerList = query.list();	//最终对象中只封装了投影属性,其他属性都为null
QBC查询
1.查询全部
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> customerList = criteria.list();

2.条件查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("gender","女"));
//模糊查询重载方式一:
criteria.add(Restrictions.like("name","张%"));
//模糊查询重载方式二:
criteria.add(Restrictions.like("name","张",MatchMode.START));
List<Customer> customerList = criteria.list();

3.排序查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("id"));		//Order.desc("实体类属性");

4.分页查询
criteria.setFirstResult("开始的索引");
criteria.setMaxResults("每页显示条数");

5.统计查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setProjection(Projections.rowCount());
Long count = (Long)criteria.uniqueResult();

6.离线条件查询(DetachedCriteria)
    DetachedCriteria可以脱离session使用;在MVC模式下,通常可以在web层使用DetachedCriteria完成对参数的封装过滤,再传参给dao层
//web层封装过滤参数
//DetachedCriteria封装了private CriteriaImpl/Criteria,因此Criteria的方法它都能使用
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//dao层绑定DetachedCriteria到session中
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> customerList = criteria.list();
Hibernate多表查询
* 内连接: HQL的内连接,会将各个对象的数据封装到各自的对象中,因此返回的结果只能用List<Object[]>来接收
List<Object[]> list = session.createQueue("from Customer c inner join c.linkManSet");
//list.get(0)--> [Customer{...,linkManSet=[LinkMan{},LinkMan{}]]
* 迫切内连接: HQL特有的连接查询,在join后面加fetch关键字,查询结果能直接封装到一个对象中,但是使用迫切内连接查询会出现重复数据,因此通常还要使用distinct关键字去重
List<Customer> customerList = session.createQueue("select distinct c from Customer c inner join fetch c.linkManSet");
* 左外连接
* 迫切左外连接(left outer join fetch)
* 右外连接
Hibernate抓取策略
Hibernate抓取策略概念:
	当查询一个持久化对象数据的时候,如何获取这个持久化对象关联的对象的策略(更准确说,使用什么样的SQL来查询关联对象),抓取策略是提升查询性能的一种方式,提升查询性能的方式主要分为:延迟加载和抓取策略

1.延迟加载:
* 类级别延迟加载:
	使用load方法查询持久化对象时,是否延迟加载,在实体类映射配置文件的class标签上配置
<class name="" table="" lazy="false">
	//lazy属性默认true,表示延迟加载
</class>
类级别延迟加载失效发方式:
	* 使用final关键字修饰持久类
	* 配置class标签的lazy属性,lazy="false"

* 关联级别延迟加载:
	查询到一个持久化对象时,是否查询出这个对象所关联的对象;关联级别的延迟往往会与抓取策略一起使用,优化程序。(关联级别的延迟在<set>或者是<many-to-one>标签上的配置延迟加载)

2.set标签上的lazy属性和fetch属性:
fetch属性: 控制以什么样的格式来查询关联对象(连接查询,子查询)
lazy属性: 控制是否延迟加载关联对象
fetch:抓取策略,控制SQL语句的发送的格式。
	* select: 默认值。发送一条select语句查询关联对象。
	* join: 发送一条迫切左外连接查询关联对象。抓取策略为join,lazy属性就会失效
	* subselect: 发送一条子查询查询关联对象。子查询的in中如果只有一个值,那么hibernate会自动优化为等号
lazy:延迟加载,控制SQL语句的发送的时机。
	* true	:默认值。采用延迟加载。
	* false	:不采用延迟加载。
	* extra	:极其懒惰。只投影查询需要的数据
测试案例: DEBUG调试A,B断点
	Customer customer = session.get(Customer.class,1L);	//A
	System.out.println(customer.getLinkManSet().size());  //B
案例一:<set fetch="select" lazy="true">
	SQL: select * from customer where id = ?;s	//A
		select * from linkman where c_id = ?;	//B
案例二:<set fetch="select" lazy="false">
	SQL: select * from customer where id = ?;	
		select * from linkman where c_id = ?;	//A
案例三:<set fetch="select" lazy="extra">    投影查询需要的数据
	SQL: select * from customer where id = ?;	//A
		select count(*) from linkman where c_id = ?;	 //B
案例四: <set fetch="join" lazy="true">		抓取策略为join,lazy属性就无效了
	SQL: select * from customer c left outer join linkman l on  c.id = l.c_id;	//A
案例五: <set fetch="subselect" lazy="true">
	SQL: select * from customer where id = ?;	//A
		select * from linkman where c_id in (?,?);	//B
案例六: <set fetch="subselect" lazy="false">	
	SQL: select * from customer where id = ?;	
		select * from linkman where c_id in (?,?);	//A
案例六: <set fetch="subselect" lazy="false">
	SQL: select * from customer where id = ?;	//A
		select count(*) from linkman where c_id in (?,?);	//B

3.many-to-one上的fetch和lazy
fetch:抓取策略,控制SQL语句的发送的格式。
	* select :默认值.发送一条select语句查询关联对象。
	* join	:发送一条迫切左外连接查询关联对象。
lazy:延迟加载,控制SQL的发送的时机。
	* proxy	:默认值。是否采用延迟,需要由另一方类上的延迟加载来决定。由一的一方的class标签上的类级别延迟加载来决定
	* false	:不采用延迟加载。
	* no-proxy:不用研究
	
4. 批量抓取,batch-size,实际上就子查询
    Query query = session.createQuery("from Customer");
    List<Customer> customerList = query.list();
    for (Customer customer : customerList) {
        for (LinkMan linkMan : customer.getLinkMans()) {
            System.out.println(linkMan);
        }
    }
	默认情况下,以上代码会发送n+1一条sql,1条sql查询customerList,n条sql查询每个customer关联的linkMan集合,这样非常影响性能
* 查询客户批量抓取联系人	
在Customer.hbm.xml中<set>标签上配置batch-size属性,属性值为自定义的批量抓取的个数
* 查询联系人批量抓取客户
在Customer.hbm.xml中<class>标签上配置batch-size属性,属性值为自定义的批量抓取的个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值