码迷,mamicode.com
首页 > Web开发 > 详细

框架 day33 Hibernate,组件映射,继承映射,抓取(检索)策略-优化,检索方式总结

时间:2016-05-22 06:21:36      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:

组件(组成)映射


例1:

public class Person {
	
	private Integer pid;	//OID 值
	private String name;
	
	//第一种方案
	private String homeAddr;
	private String homeTel;
	private String companyAddr;
	private String companyTel;

↑一般项目都都采用此方案()


*通过面向对象角度,使用设计模式(组件|组合),将数据都抽取到一个对象中。将多个对象组合在一起,达到重复利用目的。

例2:抽取数据(地址)到一个对象中, 这个值对象既为组件,组件不支持共享引用

public class Address {
	//值对象 (vo 值对象/po 持久对象/bo 业务对象)
	
	private String addr;
	private String tel;


public class Person {
	
	private Integer pid;	//OID 值
	private String name;
	//第二种方案:组合
	private Address homeAddress;
	private Address companyAddress;

组件映射配置

<hibernate-mapping>
	<class name="com.itheima.b_component.Person" table="t_person">
		<id name="pid">
			<generator class="native"></generator>
		</id>
		<property name="name"></property>
		
		<component name="homeAddress" class="com.itheima.b_component.Address">
			<property name="addr" column="homeAddr"></property>
			<property name="tel" column="homeTel"></property>
		</component>
		<component name="companyAddress" class="com.itheima.b_component.Address">
			<property name="addr" column="companyAddr"></property>
			<property name="tel" column="companyTel"></property>
		</component>
		
	</class>

</hibernate-mapping>

注意:必须确定组合javabean类型  <component class="">

每一个对象属性必须在表中都存在独有列名。<property column="...">



继承映射



应用场景:
公司的员工,保存:小时工和正式员工

员工类

public class Employee {
	
	private Integer eid;
	private String name;
小时工

public class HourEmployee extends Employee {
	
	private int rate;	//小时薪水
正式员工

public class SalaryEmployee extends Employee {
	
	private int salary; //正式薪金

简单方式

public class Employee {
	
	private Integer eid;
	private String name;
	private String temp;//标志 1;小时工2;正式工
	private int money;  //金额


继承方式1:<sub-class>


*所有内容保存一张表,给表提供表示字段,每一个子类具有独有字段
技术分享



缺点:存在null值。


配置
技术分享


继承方式2:<joined-subclass> (掌握)



*将提供三种表,主表存放基本信息,两个从表存放独有字段内容。
技术分享


表之间存在一对一关系

技术分享


一对一:
方式1:主表的主键,与从表的外键(唯一),形成主外键关系
方式2:主表的主键,与从表都主键,形成主外键关系



继承方式3:<union-class>


*将生成3张表,彼此之间没有关系,但主键值逐渐递增,需要hibernate自动维护三张表之间的主键唯一

技术分享


*缺点: 主键生成策略 increment,不能通过数据库自动生成。存在并发问题
每一次都执行select语句,从三张表中查询oid的最大值。


配置

技术分享

技术分享



抓取(检索)策略--优化



*开发中,使用都是默认值,最后进行优化,根据业务要求进行相应设置



3.1检索方式



*立即检索:在执行查询方法之后,立即执行select语句,进行查询。


技术分享

//class 标签中lazy=false 立即检索
public void loadCustomerfalse(){
	Session session=sessionFacoty.openSession();
	Transaction tx=session.beginTransaction(); 
	//该行代码让hibernate执行select语句,查询数据库
	Customer c=(Customer)session.load(Customer.class, 1);
	c.getId();
	c.getAge();
	tx.commit();
	session.close();  
}



*延迟检索:在执行查询方法之后,没有进行查询,底层生成代理对象,直到需要相应的数据,再进行查询。


技术分享

//class 标签中lazy=true 延迟检索
public void loadCustomertrue(){
       Session session=sessionFacoty.openSession();
       Transaction tx=session.beginTransaction(); 
       Customer c=(Customer)session.load(Customer.class, 1);
       //该行代码让hibernate执行select语句,
       //查询数据库(需要用的时候查数据库)
      c.getId();
      c.getAge(); 
      tx.commit();
      session.close();  
}


-相应的数据:除OID之外的值,关联数据。
-延迟加载在开发中,主要好处,延缓数据加载,在使用时才进行加载 (缩短数据在内存中时间)

-理解延迟检索中的代理

技术分享




3.2检索类型



*类级别检索:当前对象所有属性值。例如:Customer自己数据


  Customer c=(Customer)session.load(Customer.class, 1);


  session的方法直接检索Customer对象,对Customer对象到底采用立即检索 还是延迟检索方式
  通过class元素的lazy属性设定


*关联级别检索:当前对象关联对象数据。例如:Customer 关联 Order 数据


     Customer c=(Customer)session.load(Customer.class, 1);

     Set set=c.getOrders()//检索Order对象的set集合


     在这个例子中
     session.load(Customer.class, 1):查询的主体表

     c.getOrders().size():查询客体表的集合大小


     查询客体表是否发生,以何种方式发生(立即检索、延迟检索和迫切左外连接检索),就是关联级别检索

      通过set元素lazy属性设定


3.3类级别



*类级别:查询当前类的所有内容,只查询一次。优化指的是查询时机优化,让空闲时间服务器做出其他处理。
*session.get(Customer.class ,oid) 通过OID立即检索(查询),如果数据不存在返回null。
*session.load(Customer.class , oid ) 默认通过OID延迟检索,如果数据不存在将抛异常。
         类级别配置,只对load方法有效。
         Customer.hbm.xml <class name="" table=""lazy="true|false">
                   true:默认值,延迟检索
                   false:立即检索。

*应用:
-如果程序加载一个对象的目的是为了访问它的属性, 可以采取立即检索. 
-如果程序加载一个持久化对象的目的是仅仅为了获得它的引用, 可以采用延迟检索

 

3.4一对多和多对多的检索策略

*无论 <class>元素的 lazy 属性是 true 还是 false,
-Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略


*若 <class> 元素的 lazy 属性为 true 或取默认值, 
-Session 的 load() 方法不会执行查询数据表的 SELECT 语句, 仅返回代理类对象的实例, 该代理类实例有如下特征:
         >由 Hibernate 在运行时采用 javassist 工具动态生成
         >Hibernate创建代理类实例时, 仅初始化其 OID 属性
         >在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例

 

*对比
         fetch="join",lazy无效,hibernate 将使用“迫切左外连接”,底层执行sql语句就是“左外连接”
                   只执行一条select,将当前对象及关联对象数据一次性查询出来。
         fetch="select",默认值,执行多条select语句
                   lazy="false"立即执行,在执行get方法时,立即执行多条select语句。
                   lazy="true"延迟执行,在执行get方法时先查询客户Customer,直到使用Order数据时才查询Order
                   lazy="extra"极其懒惰,在执行get方法时先查询客户Customer(select t_customer),
                                     如果需要order 订单数,将执行聚合函数只查询数量(select count()t_order),
                                     如果需要详情再查询详情(select t_order))。
                   fetch="subselect",采用子查询
                   lazy取值与 fetch="select"相同。
                   注意:必须使用Query进行查询。

 


技术分享


*延迟检索和增强延迟检索


-在延迟检索(lazy 属性值为 true) 集合属性时, Hibernate 在以下情况下初始化集合代理类实例 

         >应用程序第一次访问集合属性: iterator(), size(), isEmpty(), contains() 等方法

         >通过 Hibernate.initialize() 静态方法显式初始化


-增强延迟检索(lazy 属性为 extra): 与 lazy=“true” 类似.
主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机:

         >当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders 集合代理类实例的初始化

         >当程序第一次访问 order 属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化 orders 集合类的实例, 仅通过特定的     select 语句查询必要的信息, 不会检索所有的 Order 对象

 

*用带子查询的 select 语句整批量初始化 orders 集合(fetch属性为“subselect”)
<set> 元素的 fetch 属性: 取值为“select”或“subselect”时, 决定初始化 orders 的查询语句的形式;


--若取值为”join”, 则决定 orders 集合被初始化的时机.默认值为 select 
--当 fetch 属性为 “subselect” 时
         >假定 Session 缓存中有 n 个 orders 集合代理类实例没有被初始化,
          Hibernate 能够通过带子查询的 select 语句, 来批量初始化 n 个 orders 集合代理类实例

 

*迫切左外连接检索(fetch 属性值设为 “join”)

-当 fetch 属性为 “join” 时:
>检索 Customer 对象时, 会采用迫切左外连接(通过左外连接加载与检索指定的对象关联的对象)策略来检索所有关联的 Order 对象
>lazy 属性将被忽略
>Query 的list() 方法会忽略映射文件中配置的迫切左外连接检索策略, 而依旧采用立即检索还是延迟加载策略由set集合的lazy属性决定

 



3.5多对一和一对一关联的检索策略



*共同特点拥有一方(<many-to-one> /<one-to-one>)

 


技术分享\

fetch="join" , lazy 无效,hibernate使用“迫切左外连接”,一次性查询订单和关联客户
                  
fetch="select" 查询多条select语句
         lazy="false"立即 ,执行两条select语句
         lazy="proxy"代理,order关联客户Customer,客户是否延迟,取决客户类级别检查策略。
                   Customer.hbm.xml<class lazy="false"> 立即客户
                   Customer.hbm.xml<class lazy="true"> 延迟客户
         lazy="no-proxy"不研究


*批量检索  从一的一端查询  查询所有的客户

-<set> 元素有一个 batch-size 属性, 用来为延迟检索策略或立即检索策略设定批量检索的数量. 
   批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能.  默认值是1
注:query.list()属于hql检索,hql检索忽略关联级别的迫切左外连接检索,只与lazy属性有关.

配置

 

技术分享


批量检索  从多的一端查询  查询所有的订单
-在Customer.hbm.xml文件中增加batch-size属性
技术分享


*比较三种检索策略

技术分享




检索方式总结


1、检索方式

1.使用OID获取

       >session.get(User.class,1);立即加载如果不存在,就返回null

       >session.load(User.class,2); 延迟加载 如果不存在,就抛异常

PS:使用以上两个方法进行查询,结果都为持久态对象,持久对象就在一级缓存中。

2.导航对象图检索方式

>customer.getOrderSet().size()

3.使用HQL

       >session.createQuery("FROMEmployee e WHERE e.id>? ORDER BY e.id DESC").list();

4.原生的SQL方式

       >session.createSQLQuery(Stringsql);

5.QBC 检索方式: 使用 QBC(QueryBy Criteria) API 来检索对象.

Query By Criteria提供 纯面向对象查询语句


2、 HQL 是 Hibernate最常用检索方式

 

*与SQL语法基本一致,不同的是HQL是面象对象的查询,查询的是对象和对象中的属性

*HQL的关键字不区分大小写,但类名和属性名区分大小写

技术分享


支持 所有 SQL支持检索方式

 

步骤 :

   1) 获得Session

   2) 编写HQL

   3) 通过 session.createQuery(hql) 创建Query对象

   4) 为Query对象 设置条件参数

   5) 执行查询 list() ---- 返回一个集合列表 、 uniqueResult();--- 返回一个查询结果  

 

* Qurey 接口支持方法链编程风格  ,将上面所有步骤写入一句程序代码中

 

3、 编写测试用例,创建初始数据

创建4个Customer , 每个Customer 创建 10个 Order

 

4、 简单查询, hibernate 企业开发主流查询 HQL 和 QBC

 * 查询所有数据

              //HQL
              Stringhql = "from Customer";
              Queryquery = session.createQuery(hql);
              List<Customer>list = query.list();
              System.out.println(list);
 
              //QBC
              Criteriacriteria = session.createCriteria(Customer.class);
              List<Customer>list2 = criteria.list();
              System.out.println(list2);

  *HQL 和 QBC 都支持链式编程写法

            List<Customer>list3 = session.createQuery("from Customer").list();


5、 本地SQL 检索

       *编写及其复杂的查询,企业内部大多使用 SQL语句

//内连接 写法一 : select *from A inner join B on A.id = B.A_id;
//内连接 写法二 (隐式): select* from A,B where A.id = B.A_id ;
Stringsql = "select * from customers 
	,orders where customers.id =orders.customer_id and customers.name = ?";
SQLQuerysqlQuery = session.createSQLQuery(sql);
//设置参数
sqlQuery.setParameter(0,"mary");
Listlist = sqlQuery.list();
System.out.println(list);

       *当返回很多列时,默认将每条记录保存在 Object[]中, 返回 List<Object[]>

       *将返回结果 与实体类 绑定,将每条数据 转换实体类对象

String sql = "select orders.* from customers 
	,orders where customers.id = orders.customer_id and customers.name = ?";
sqlQuery.addEntity(Order.class);


6、 编写HQL时,通过as关键字 为类 起别名

  from Customer as c where c.name=:custname             

   原来写法: from Customer wherename=:custname

   使用别名时 ,as可以省略 fromCustomer c where c.name=:custname

 

* 别名主要使用关联复杂查询时

 

7、 多态查询

   hibernate 检索一个类 对应数据时, 将类所有子类(PO类) 对应数据表记录返回

 session.createQuery("fromjava.lang.Object").list();

 * 将Object 所有子类 对应数据表的 数据查询返回

 

from 关键字后面,如果PO类,省略包名, 如果不是PO类,必须写完整包名类名

 

8、 查询结果排序

//HQL
Stringhql = "from Customer order by name asc";
Listlist = session.createQuery(hql).list();
System.out.println(list);
 
//QBC
Listlist2 =session.createCriteria(Customer.class)
	.addOrder(org.hibernate.criterion.Order.asc("name")).list();
System.out.println(list2);

9、 分页查询

Query 接口和 Criteria 接口 都提供 setFirstResult 、setMaxResults 两个方法,用于分页查询

       *  setFirstResult 起始记录索引,第一条数据 索引 0

       *  setMaxResults 查询返回记录条数

       案例:

              //分页查询,返回 25-34条订单
              //HQL
              Stringhql = "from Order";
              Queryquery = session.createQuery(hql);
              //设置分页参数
              query.setFirstResult(24);// 索引 是 起始记录 -1
              query.setMaxResults(10);   
  

10、 检索单一对象  query.uniqueResult() 、 criteria.uniqueResult()

   * 该方法主要用于,只有1条数据结果

   * 什么情况只有一条结果 : 用户登录、使用聚集函数 sum、count、avg、max、min

//查询mary的信息
Customercustomer = (Customer) session
	.createQuery("from Customer where name ='mary'").uniqueResult();
System.out.println(customer);
 
//使用聚集函数 -- 查询客户最大年龄
Integerage = (Integer) session
	.createQuery("select max(id) fromCustomer").uniqueResult();
System.out.println(age);  
           

如果查询结果 只有一条记录或者 无记录,使用uniqueResult 是没问题的, 但是如果查询结果大于 一条记录,报错

org.hibernate.NonUniqueResultException:query did not return a unique result: 4

 

===============================================================================================================================

11、 带有参数条件的查询 (重点)

1) 单表条件查询

HQL写法:

Customer customer1 = (Customer)session.createQuery("from Customer where name = ?")
	.setParameter(0,"tom").uniqueResult();
Customer customer2 = (Customer)session.createQuery("from Customer where name =:cname")
	.setParameter("cname", "tom").uniqueResult();

QBC写法:

Customer customer3 = (Customer)session.createCriteria(Customer.class)
	.add(Restrictions.eq("name","tom")).uniqueResult();

       *Restrictions 用来添加查询条件 ,面向对象条件查询

 

将参数绑定到一个持久化对象

Customercustomer = new Customer();
customer.setId(1);
Listlist2 = session.createQuery("from Order where customer =?")
	.setEntity(0, customer).list(); // 通过customer_id 查询

* 简化为

List list = session.createQuery("from Order where customer.id =?")
	.setParameter(0, 1).list(); 

* setEntity 关联对象 ,必须要有OID ,否则会报错

 

使用QBC 为参数绑定 持久化对象

Listlist3 =session.createCriteria(Order.class)
	.add(Restrictions.eq("customer",customer)).list(); // 通过customer_id 查询

2) 多表条件查询

技术分享

hibernate  HQL 支持7种 连接写法

       *(SQL标准)内连接 inner join  可以省略 inner,直接 join

       *迫切内连接 inner joinfetch  ------ 不是SQL写法,是hibernate 提供

       *隐式内连接 不写任何关键字,完成表关联

      

       *(SQL标准)左外连接 left outer join ,可以省略 outer ,直接 left join

       *迫切左外连接 left outerjoin fetch ----- 不是SQL语法

       *(SQL标准)右外连接 right outer join

      

       *(SQL标准)交叉连接 (笛卡尔积 )

 

问题: 区分内连接和迫切内连接,左外连接和迫切左外连接

       *左外连接

List list =session.createQuery( "from Customer c left outer joinc.orders").list(); 
返回 List<Object[]>

       每个数组两个元素 ,一个Customer 一个Order

       *迫切左外连接  

List list =session
	.createQuery("select distinct c from Customer c left outer joinfetch c.orders").list();

       返回 List<Customer> 保存所有Customer对象,需要distinct 排重重复

 

问题:多表关联条件查询,隐式内连接 和 QBC方式  

//隐式内连接 o.customer 当做Customer类数据表
List<Order>list = session
	.createQuery("from Order o where o.customer.name =?")
	.setParameter(0, "mary").list();
 
//QBC 连接查询,必须使用 criteria.createAlias()
 
Criteriacriteria = session.createCriteria(Order.class);
criteria.createAlias("customer","c"); // 为订单关联Customer属性起了别名
criteria.add(Restrictions.eq("c.name","mary"));
Listlist2 = criteria.list();

       *  在 createAlias 默认使用 inner join 内连接

              criteria.createAlias("customer","c", Criteria.LEFT_JOIN); 在关联时使用左外连接

      

12 、投影查询

       查询结果仅包含实体的部分属性

       *  查询Customer的所有 name,age 属性

HQL方式

       

session.createQuery("selectname,age from Customer"); 
返回 List<Object[]>

       *将结果保存Customer对象中,提供name和age 构造方法

       session.createQuery("selectnew Customer(name,age) from Customer"); 
返回 List<Customer>

可以将查询结果 保存List 或者 Map集合     

       *select new list(name,age) from Customer

       *select new map(name,age) from Customer

      

QBC方式 (开发中不用,非常麻烦)

       Listlist3 = session
                            .createCriteria(Customer.class)
                            .setProjection(
                                          Projections.projectionList()
                                                        .add(Property.forName("name"))
                                                        .add(Property.forName("age"))).list();
 

13、 分组统计查询

       count  sum avg max min

       *Long count = (Long) session.createQuery("select count(*) fromOrder").uniqueResult();
       *List list2 = session.createQuery("select count(*) from Order group bycustomer").list();
 

14、 命名查询语句

   在开发中 hql语句 写到代码中,不方便维护, 将HQL定义到配置文件中 ------------ 命名查询语句

 

在hbm映射文件 (也可以用注解配置)

       <!--这里可以定义命名查询 -->
       <!--       定义 HQL 语句 <queryname=""></query> -->
       <!--       定义 SQL 语句 <sql-queryname=""></sql-query> -->
       <queryname="findCustomerByName">
              <![CDATA[fromCustomer where name = ?]]>
       </query>

* 为hql语句 起了一个名字

 

程序代码

       Queryquery = session.getNamedQuery("findCustomerByName");
       query.setParameter(0,"tom");
       Customercustomer = (Customer) query.uniqueResult();


15、 离线Criteria对象 --- DetachedCriteria

       *主要用于javaee分层开发,可以在web层封装查询条件,传递数据层 关联Session进行查询

       DetachedCriteriadetachedCriteria = DetachedCriteria.forClass(Customer.class);
       detachedCriteria.add(Restrictions.eq("name","kitty"));
 
       //传递数据层
       Sessionsession = HibernateUtils.openSession();
       Transactiontransaction = session.beginTransaction();
 
       //将离线查询对象 关联到Session
       Criteriacriteria = detachedCriteria.getExecutableCriteria(session);
       Customercustomer = (Customer) criteria.uniqueResult();


HQL和QBC比较: 两种查询功能类似, 简单查询建议编写HQL,对于复杂查询,多条件组合查询 建议编写 QBC方式

 技术分享

============================================================================================================================

 




框架 day33 Hibernate,组件映射,继承映射,抓取(检索)策略-优化,检索方式总结

标签:

原文地址:http://blog.csdn.net/opopopwqwqwq/article/details/51473127

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!