多表关联情况下,如果想在控制台输出对象,需要有一方的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();
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"));
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层
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
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");
* 迫切内连接: 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">
</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);
System.out.println(customer.getLinkManSet().size());
案例一:<set fetch="select" lazy="true">
SQL: select * from customer where id = ?;s
select * from linkman where c_id = ?;
案例二:<set fetch="select" lazy="false">
SQL: select * from customer where id = ?;
select * from linkman where c_id = ?;
案例三:<set fetch="select" lazy="extra"> 投影查询需要的数据
SQL: select * from customer where id = ?;
select count(*) from linkman where c_id = ?;
案例四: <set fetch="join" lazy="true"> 抓取策略为join,lazy属性就无效了
SQL: select * from customer c left outer join linkman l on c.id = l.c_id;
案例五: <set fetch="subselect" lazy="true">
SQL: select * from customer where id = ?;
select * from linkman where c_id in (?,?);
案例六: <set fetch="subselect" lazy="false">
SQL: select * from customer where id = ?;
select * from linkman where c_id in (?,?);
案例六: <set fetch="subselect" lazy="false">
SQL: select * from customer where id = ?;
select count(*) from linkman where c_id in (?,?);
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属性,属性值为自定义的批量抓取的个数