hibernate框架基础知识

  框架:都是基于MVC实现,大多都是通过配置文件说明各层之间的关系,甚至同一层内部的关系,让程序可扩展性好、重用性高、高内聚、低耦合          、易于维护、关系的说明不要硬编码、可以实现软件热插拔。
    MVC :也可以做到上面提到的理想。
    简历模板:相当于框架。框架的强大之处不在于让你做什么,而是不让你做什么。


    0.好处:
      1)忽略表现形式,关注业务本事      
      2)保证质量
      3)风格一样,阅读方面
      4)维护方便


    1.Hibernate框架


      http://hibernate.org/orm/downloads/
      Latest version: Hibernate是在2001年发起的开放源代码项目,Hibernate5.X
      hibernate-release-4.3.1.Final


      Hibernate创始人,原来SQL语句都不是太精通,开始利用JDBC操作数据库,有很多操作都是频繁的在重复。
      程序访问数据库,对于数据库的操作都是要执行SQL命令。创始人致力于将用户的操作需求拼装成合法的SQL命令,将结果的解析以及封装帮忙
      实现,让对于数据库操作完全的体现面向对象的思想。保存时,用户提供对象,检索时帮助封装成对象。
      
      解决方案:根据表的结构,定义和它相关的类,表对应一种类型,类中属性和表的字段对应,提供一个表和类关联关系的文件(用于说明一种
      对应关系——表和类、列和属性),希望文件编辑语言及格式和平台以及程序语言无关(XML文件)。


      1-1.What:是一种持久化业务实现的框架技术。


 持久化:程序中瞬时态数据-->持久化(保存到相关存储介质)的状态
 Eg: XXXObj  ---> DataBase
             DabaBase---> XXXObj (Memory)
          框架:是个半成品,开发的时候在框架的基础上进行,保证程序质量(不至于太差),框架是由若干类以及接口组成,按照某种业务策略
在底层完成很多业务。


      1-2.Why:对于数据库及对象持久化业务实现,更加简单,门槛更低(甚至可以说,不懂SQL命令,利用Hibernate,同样可以操作数据库)。
      1-3.How:
      1-4.Where or When:
      1-5.Object Relational Mapping(ORM):我们编写程序时,以面向对象的方式处理数据,保存数据的时候,却以关系型数据库的方式来存储  ,所以,客观上我们需要一种能在两者之间进行转换的机制,这种机制称为ORM。Hibernate就是ORM实现机制的一个代表。
      1-6.Hibernate核心接口:
 1)Configuration:读取Hibernate.cfg.xml配置文件,配置、启动Hibernate。
   Eg:
               Configuration config = new Configuration();
      config.configure("/hibernate.cfg.xml");
 2)SessionFactory:初始化Hibernate,充当数据存储源的代理,可以创建session对象。
  XXX.hbm.xml
  ...
   Eg:
      SessionFactory sessionFactory = config.buildSessionFactory();
      
 3)Session:是对JDBC应用中Connection的封装,但是和HttpSession没关系,通过它可以操作数据库。
   增删改查:save(XXXObj) update(XXXObj) get(Class clazz,uid) load(uid) delete()
   Eg:
      // 创建session对象,从而为查询遍历做准备
      Session session = sessionFactory.openSession();
      a.save(Object obj):持久化,将对象序列化到数据库。
      b.get(Class clazz, Serializable arg1):arg1是数据库中一条记录的唯一ID值(关键字)。
Customer customer = (Customer)session.get(Customer.class, 23);
System.out.println(customer.getCustName() + "\t" + customer.getCustAge());
      c.update(Object obj):对于持久态的对象来说,多次修改操作,在没有最终提交之前,都是在缓存中进行,提高资源利用率。
update customers set custName=?, custTel=?, custAddress=?, custGender=?, custAge=? where custId=?
      d.delete(Object obj):删除的时候,要注意只能删除数据库中有的对象,只要保证你删除是持久化(纳入session管理的)的对象
                   ,就一定可以实现。
        如果传入的参数是游离对象,先使游离对象被当前Session关联,使它变为持久化对象,如果传入的参数是持久化对象,则忽略这 一步。
计划执行一个delete语句。
把对象从Session缓存中删除,该对象进入删除状态。
值得注意的是,Session只有在清理缓存的 时候才会执行delete语句.

      e.load(Class clazz, Serializable id)与get(Class clazz, Serializable id):用于从数据库检索数据到session缓存中。
区别主要在于加载时机,get方法是立即加载(直接访问数据库),当数据库没有检索的对象时候,会返回null对象,而load方法
主要是进行延迟加载(lazy),延迟加载是在需要的时候才去检索,而load方法执行后,获得是相关对象的OID,然后,根据需要
(真的要使用检索对象的信息),才去执行SQL命令。为了最大限度的节省系统资源。
如果使用load方法检索没有对应OID的对象,会报ObjectNotFoundException异常。
Eg:
  Customer customer = (Customer)session.get(Customer.class, 22);   // 立即检索
  Serializable oid = session.load(Customer.class, 21);             // 延迟检索
  Customer customerTemp = (Customr)oid;
  System.out.println(customerTemp.getCustName());
f.clear():清空session缓存中的所有的持久化对象(将会从持久态转换为游离态)。
 update(obj);
 update(obj);
 对于一个持久态的对象来说,当情况session的时候,一定会执行一个update.
 
g.evict(obj):清空session缓存中指定的持久化对象。
h.saveOrUpdate():如果数据中没有,保存(添加),如果有,修改。
 Session的saveOrUpdate()方法同时包含save()与update()方法的功能,如果传入的参数是临时对象,就调用save()方法,如果传  入的参数是游离对象,就调用update()
 Session的update()、saveOrUpdate()和lock()方法使游离对象状变为持久化对象
i.merge():Session的merge方法能够把一个游离对象的属性复制到一个持久化对象中
 
 4)Transaction:事务接口,是逻辑单元实现机制,非查询操作时,使用事务机制。
如何划分一个事务呢?从事务的对象创建开始,到要么回滚要么提交操作。
   Eg:
      // 通过session对象,开启一个事务对象Transaction
      Transaction transaction = session.beginTransaction();
   Methods:
   commit():提交
   rollback():回滚


 5)Query:HQL查询接口,引用一个可以解析查询的对象。
 6)Criteria:查询接口,面向对象的一种查询操作。


 操作数据库的流程:
 a.查询:
a-1.创建Configuration对象,装载Hibernate.cfg.xml信息,启动Hibernate.
a-2.创建SessionFactory对象,装载所有的对象映射文件。
a-3.创建session对象,从而为查询遍历做准备。
a-4.通过session的相关查询方法,执行对象级的检索。
a-5.关闭session,就是清空缓存,释放资源。
 b.非查询:
b-1.创建Configuration对象,装载Hibernate.cfg.xml信息,启动Hibernate.
b-2.创建SessionFactory对象,装载所有的对象映射文件。
b-3.创建session对象,从而为查询遍历做准备。
b-4.通过session对象,开启一个事务对象Transaction。
b-5.通过session的相关非查询方法,执行持久化业务。
b-6.关闭session,就是清空缓存,释放资源。


      1-7.Hibernate.cfg.xml:Hibernate配置文件,其中用于说明如何访问操作数据库。存入项目的src根路径下面。
 Demo: hibernate-release-4.3.1.Final\project\etc\hibernate.cfg.xml
 a.hibernate-configuration:根节点。
   a-1.session-factory:自定义一个名字。
a-1-1.<property name="XXX配置信息名称">value</property>
     ...
a-1-2.<mapping resource="对象映射文件路径表达"/>
     ...


 b.XXX配置信息名称: 
   Demo: hibernate-release-4.3.1.Final\project\etc\hibernate.properties
   ## Oracle


   property:dialect -->value:org.hibernate.dialect.Oracle8iDialect
   property:dialect -->value:org.hibernate.dialect.Oracle9iDialect
   property:dialect -->value:org.hibernate.dialect.OracleDialect
   property:connection.driver_class -->value:oracle.jdbc.driver.OracleDriver
   property:connection.username -->value:ora
   property:connection.password -->value:ora
   property:connection.url -->value:jdbc:oracle:thin:@localhost:1521:orcl
            property:connection.url -->value:jdbc:oracle:thin:@localhost:1522:XE
   property:show_sql  -->value:true(执行持久化业务时,相关SQL命令,会显示在控制台)
 c.项目中关系对象映射文件添加到Hibernate.cfg.xml
   tag: 
mapping:通过它加载关系对象映射文件。
resource: 关系对象映射文件的路径表达,在表达路径时,将包名的分隔符换成"/"。
   Eg:
   <mapping resource="com/hd/netstore/entity/Customer.hbm.xml"/>
   ...


      1-8.XXX.hbm.xml:关系对象映射文件,说明表和类的对应关系。
 命名:XXX是和某个实体类的类名一样的。
 保存位置:和XXX.java在同一个地方(package)。
 三大范式:
 a.第一范式:列原子性,每个列不可再分。
 b.第二范式:在第一范式的基础上,要求每个列和主键相关。
     Fresher(empNo,empName,empAge,empTel,empScore)


 c.第三范式:在第二范式的基础上,要求每个列和主键直接相关。
     Fresher(empNo,empName,empAge,empTel)
     empScore是和某次(科目+时间)有关。
   对于违背第三范式的情况,如何处理呢?
   拆出新的表,添加关联。
   Fresher(empNo,empName,empAge,empTel)
   Scores(scoreid,scoreTime,empNo,score)


 Demo:hibernate-release-4.3.1.Final\hibernate-release-4.3.1.Final\project\build\classes\test\hibernate-core\org\hibernate\test\schemaupdate
 Format:
<hibernate-mapping package="org.hibernate.test.schemaupdate">


<class name="Version" table="tableName">
<id name="id">
<generator class="org.hibernate.id.TableHiLoGenerator">
                <param name="table">uid_table</param>
                <param name="column">next_hi_value_column</param>
        </generator>
</id>
<property name="attributeName" column="tableColumnName" type="attribute's type"/>
...
</class>


</hibernate-mapping>
 root:hibernate-mapping 
 class:某个实体类的名字(name),还有对应的表名(table)。

id:每个表都要有主键,id就是用于说明XXX类对应的那个表的主键信息。
  name="attributeName" column="columnName" type="java.lang.Integer"
  generator:说明主键的生成策略。assigned、sequence
     <generator class="sequence">
   
<param name="sequence">seq_contid</param>
   
     </generator>
     <generator class="assigned">
    <!-- 用户自定义 -->
 
     </generator>
                property name="quName" column="quname" type="java.lang.String"
...

      1-9.Hibernate工程的应用步骤
 a.创建工程(Java project || Dynamic web project)
 b.添加Hibernate资源jar包。add build path


   http://hibernate.org/orm/downloads/
   hibernate-release-4.3.1.Final:
   documentation:开发指南devguide-->index.html,Hibernate API
   lib:hibernate-release-4.3.1.Final\lib\required(必须的)  
   project:hibernate-release-4.3.1.Final\project\etc\配置文件DEMO

 c.给工程添加Hibernate配置文件。
 d.根据业务要求,需求分析,创建表。
   http://192.168.0.116:5560/isqlplus


   customers(custId,custName,custTel,custAddress,custGender,custAge)
   orders(orderId,custId,orderTotal,orderTime)
   create table list:
   create table customers(
custId integer primary key,
custName varchar2(100) not null,
custTel varchar2(20) not null,
custAddress varchar2(30) not null,
custGender varchar2(2) check(custGender in ('M','W','O')),
custAge integer check(custAge > 0 and custAge <= 290)
   );
   create sequence seq_custId
   start with 1
   increment by 1
   nomaxvalue;
   
   create table orders(
orderId integer primary key,
custId integer references customers(custId),
orderTotal number check(orderTotal >= 0),
orderTime date default sysdate
   );
   create sequence seq_orderId
   start with 1
   increment by 1
   nomaxvalue;


 e.实体类(一般情况下,有什么表,就有什么实体类,建议表的列名尽量和实体类对应)。
   要求:属性和对应表的列对应
 每个属性要有SET和GET方法
 一定要一个无参的构造方法,因为在利用反射技术生成对象时,调用的是无参的构造方法
 实体类要实现序列化接口Serializable
 f.创建实体类和表对应的对象映射文件XXX.hbm.xml。
   
 g.Dao层,业务实现类。是数据库的操作,基于不同表,设计专门的Dao类。
   实现其业务功能。
 h.编写业务调度,通过Hibernate实现持久化业务。 
      1-10.Session的缓存:就是所谓的一级缓存,由于在Hibernate中要进行对象级的操作,所以,对象状态很重要。
  Session具有一个缓存,位于缓存中的对象称为持久化对象,为了提高资源利用率,将一些对象存入缓存中,方便修改、查询,减少直接   访问次数,节省系统开销。
           a.Session缓存中的对象和数据库中的相关记录对应,Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步     更新数据库,这一过程称为清理缓存(flush).
           b.在Session接口的实现中包含一系列的Java集合,这些Java集合构成了Session的缓存,只要Session实例没有结束生命周期,存放在其     缓存中的对象也不会结束生命周期。
  c.session调用close方法时候,会清空缓存。
  d.第一次执行get方法时候,回去缓存中查找是否有指定ID的对象存入,如果不存在,才去查询数据库,并且还将对象保存到缓存汇中,
    当再次查询时候,就可以从缓存中读取,如下两次读取,实际上是同一个对象。
    Customer customerFirst = (Customer)session.get(Customer.class, 22);
Customer customerSec = (Customer)session.get(Customer.class, 22);
System.out.println(customerFirst.equals(customerSec));


      1-11.实体对象状态:
  a.临时状态(transient):就是一个对象的创建之后,此时,就是临时状态。
    刚用new调用构造方法创建对象,还没有持久化,并不处于Session的缓存中,处于临时状态的对象称为临时对象.


  b.持久态(persistent):是指那些已经纳入session缓存管理的对象(都是和数据库相关记录对应的),它们的状态就是持久态。
    方式:添加对象的时候,在持久化数据库的同时,session的缓存中也保存了一份。
  查询某个对象,session的缓存中也保存了一份。
  c.游离状态(detached):已经被持久化,但不再处于Session的缓存中,处于游离状态的Java对象被称为游离对象.
  Eg1:
  


           // 持久态-->游离态
session.clear();
customer.setCustAge(6);
customer.setCustAge(9);
 
  // Session的update()、saveOrUpdate()和lock()方法使游离对象状变为持久化对象。
// 游离态(数据库中,脱离了session管理)-->持久态(再次纳入session管理)
     session.update(customer);
     transaction.commit();
     session.close();
 Eg2:利用持久态对象脏检查机制,如果是游离态的对象,在session清空时,不会执行脏检查。
 Configuration config = new Configuration();
config.configure("/hibernate.cfg.xml");
// 创建SessionFactory对象,装载所有的对象映射文件
SessionFactory sessionFactory = config.buildSessionFactory();
// 创建session对象,从而为查询遍历做准备
Session session = sessionFactory.openSession();
Customer customer = (Customer)session.get(Customer.class, 21);                 // 立即检索
Transaction transaction = session.beginTransaction();
// 持久态-->游离态
session.clear();
customer.setCustAge(6);
customer.setCustAge(9);
System.out.println(customer.getCustAge());
// 检验游离态
transaction.commit();
session.close();
     1-12.关联检索:通过Hibernate,实现对相关联检索。
 已知一个客户,通过相关关系的确定,直接得到他的卡
 已知一张卡,通过相关关系的确定,直接得到拥有它的客户
          分析解决方案:需要分析实体间的关系,并将它们关联信息体现到对象映射文件以及实体类中。


 E-R:entity relationship
     Customer
     Good
     Order
     OrderItem
 
          a.one to one:一对一,比如:客户VS会员卡(要求一个客户只能有一张卡,此时就是一对一关系)
   Eg:已知一个对象,可以获得另外一个对象


      a.对象映射文件:
a-1.Customer.hbm.xml:
    <class>
    <one-to-one name="idCard" class="com.hd.netstore.entity.IdCard" property-ref="customer">
    </one-to-one> 
    被引用的,相当于主表
    Attributes:
    name:外键方所在类型的一个属性名。
            class:关联的对象所在类型。
    property-ref:对方通过什么样的属性和当前对象关联。


                 a-2.IdCard.hbm.xml:
                     
   <many-to-one name="customer" column="custId" class="com.hd.netstore.entity.Customer" unique="true">
   </many-to-one>
   Attributes:
           name:指定被引用的对象在当前实体类中属性名。
   column:当前实体对应表的的外键。
     class:被关联对象的类型。
   unique:true,相当于1对1.


               b.实体类:
public class Customer implements Serializable {

private int custId;
private String custName;
...
private IdCard idCard;
...



}

                 create table idcards(
cardId integer primary key,
cardNumber varchar2(30) not null,
custId integer references customers(custId)
);
create sequence seq_idcard
start with 1
increment by 1
nomaxvalue;


public class IdCard implements Serializable {

private int cardId;
private String cardName;
...
private Customer customer;
...


}


   Class Task1:国家和首都之间的关系,利用Hibernate实现关联检索。
   Eentity:
   Countries(cId,cName,cNumber,cArea)
   Captials(capId,capName,cId)
   define tables:
   1)define countries:
     create table countries(
cId integer primary key,
cName varchar2(100) not null,
cNumber integer check(cNumber > 0),
cArea number check(cArea > 0)
     );
     create sequence seq_cid
     start with 1
     increment by 1
     nomaxvalue;


              insert into countries values(seq_cid.nextval,'China',13,96000000);
     insert into countries values(seq_cid.nextval,'Japan',3,100);
   2)define captials:
     create table captials(
capId integer primary key,
capName varchar2(100) not null,
cId integer references countries(cId)


     );
     create sequence seq_capid
     start with 1
     increment by 1
              nomaxvalue;
     insert into captials values(seq_capid.nextval,'BeiJing',1);
     insert into captials values(seq_capid.nextval,'Washton',2);
     insert into captials values(seq_capid.nextval,'ToKyo',3);
   3)define entity:
     public class Country {

...
private Captial captial;
// 设置SET以及GET方法


     }
     public class Captial {

...
private Country country;
// 设置SET以及GET方法


     }
   4)mapping file:
   5)向Hibernate.cfg.xml文件中添加映射文件
     
 b.one to many:一对多,比如:客户VS订单
   希望一对多的一方,有一个存储多个多方对象集合,该集合应该是一方的类中一个属性。
   
   Customer
   Order
   Class Task2:城市和街道之间的关系,利用Hibernate实现关联检索。


 c.many to one:多对一,比如:订单VS客户
   <many-to-one >
   双向一对多关联:
   1)一对多关系中一方:
      <set name="orders" cascade="save-update" >
<key column="custId"/> orders表的外键
<one-to-many class="com.hd.netstore.entity.Order" />
      </set>

               // 添加对Order集合的属性
          private Set<Order> orders = new HashSet<Order>();    
    
      public Set<Order> getOrders() {
return orders;
      }
      public void setOrders(Set<Order> orders) {
this.orders = orders;
      }
   2)一对多关系中多方:
              <many-to-one name="customer" class="com.hd.netstore.entity.Customer" column="custId" lazy="false">
     </many-to-one>
     // 添加多对一关联时的一方
     private Customer customer;

     public Customer getCustomer() {
return customer;
     }
     public void setCustomer(Customer customer) {
       this.customer = customer;
     }


 d.many to many:多对多,比如:老师VS学生
            标签:<many-to-many> </many-to-many>
   注意:多对多关系,在使用Hibernate进行级联关系设置的时候,要将关系制定成一个表(关系表:其中的列是来自于多对多双方表的
 主键,而且在关系表中,以复合主键的方式存在,每一个列又是相关表的外键)。
   Employees(empId,empName,empAge):empId-->pk
   create table employees(
empId integer primary key,
empName varchar2(100) not null,
empAge integer check(empAge > 0 and empAge <= 65)


   );
  create sequence seq_emp
  start with 1
           increment by 1
           nomaxvalue;
           insert into employees values(seq_emp.nextval,'James',31);
           insert into employees values(seq_emp.nextval,'Wade',35);
  insert into employees values(seq_emp.nextval,'YaoMing',37);
  insert into employees values(seq_emp.nextval,'Boss',31);
           insert into employees values(seq_emp.nextval,'Kuli',28);
  insert into employees values(seq_emp.nextval,'KD',31);


   Projects(projId,projName):      projId-->pk
   create table projects(
projId integer primary key,
projName varchar2(200) not null


            );
   create sequence seq_proj
   start with 1
            increment by 1
            nomaxvalue;
            insert into projects values(seq_proj.nextval, 'BaBa');
   insert into projects values(seq_proj.nextval, 'IBM');
            insert into projects values(seq_proj.nextval, 'Microsoft');
   insert into projects values(seq_proj.nextval, 'Dell');
   
   projandemp(pjdEmpId,pjdProjId): (pjdempId,pjdProjId)-->pks
   create table projandemp(
pjdeEmpId integer not null references employees(empId),
pjdProjId integer not null references projects(projId)


            );
   alter table projandemp
   add primary key (pjdeEmpId,pjdProjId);


   设想:阿里巴巴项目组(projid=1),添加三个人(James 1,Wade 2,YaoMing 3)
   insert into projandemp values(1,1);
     insert into projandemp values(1,2);
   insert into projandemp values(1,3);
   
   insert into projandemp values(2,1);
     insert into projandemp values(2,2);


   


   d-1.单向多对多关联:单从一方关联另一方
   d-2.双向多对多关联:双方各有关联,称为双向多对多关联
       1)Emp--->Proj


Employee.java:
public class Employee {


private Set<Project> projects = new HashSet<Project>();
// 添加SET以及GET方法


}
2)Employee.hbm.xml:
  <set name="projects" cascade="save-update" table="projandemp" lazy="false">
key中的column是关系表中和当前表相关的键(是关系表的外键,并且和当前表相关)
<key column="pjdeEmpId" />
many-to-many中的column是当前实体关联的多方在关系表中的相关列(是关系表的外键)


        <many-to-many class="com.hd.netstore.entity.Project" column="pjdProjId" />
          </set>
  
Proj-->Emp
Project.java
public class Project {


}
Project.hbm.xml
<set name="employees" cascade="save-update" table="projandemp" lazy="false">
<key column="pjdProjId"/>
        <many-to-many class="com.hd.netstore.entity.Employee" column="pjdeEmpId" />
               </set>
   Class Task3:学生和老师之间的关系,利用Hibernate实现关联检索。


      1-13.在一对多或多对多关系映射的时候,实体类中表达映射集合的类型以及映射文件中的标记:
  1-13-1.set <---> <set>
 映射文件中set配置:
 name属性:指定一对多关系中,一方的所在Java类型的指定属性。  
                  table属性:指定多方的表名。
 
lazy属性:默认值为true,表示对集合使用延迟检索策略。
 
element属性:指定和Set集合中元素对应的字段(多方的列名称),并且指定元素的数据类型。
 one-to-many属性:如果Set集合元素就是多方实体类型,此时,在one-to-many子元素的class属性中设置多方类型名称。


 a.只关联多方的某个元素(element):
           <set name=“orders_columnNames” table=“orders” lazy=“true” >

<key column=“customer_id” />

<element column=“orders_columnName” type=“XxxType” not-null=“true” />
   
</set>
   b.关联多方的整个实体:
   <set name=“orders” table=“orders”lazy=“true” >

<key column=“customer_id” />

<one-to-many class=“Order” />    
   </set>
 1-13-2.Collection List <---> <bag>
 a.只关联多方的某个元素(element):
   注意:bag是对于关联检索时,允许多的一方可以有重复元素。


   <bag name="orderPriceList " table=“orders" lazy="false" >

<key>
      
<column name ="customer_id" not-null="true"></column>

</key>

<element column=“orderPrice" type=“double" not-null="true" /> 
   
</bag>  
 b.关联多方的整个实体:
   inverse="true"将控制权交给多方。
     <bag name="orderList" table="orders" lazy="false" cascade="all" inverse="true">

<key column="customer_id" />

<one-to-many class="com.netstore.entity.Order" />
   <bag>  


 1-13-3.一对多单向关联:
以Customer和Order之间的关系为例,一对多单向关联是指一个Customer可以和多个Order关联,而反过来不存在多对一的关联。
只需要在一的一方相关实体类和对象映射文件中设置。


 1-13-4.一对多双向关联:
以Customer和Order之间的关系为例,一对多双向关联是指同时包含Customer到Order的一对多关联,又存在从Order到Customer的         多对一关联。  
需要在双方相关实体类和对象映射文件中设置。
 
      1-14.lazy:在延迟检索的时候,fetch(关联的方式)属性的取值不能够是join,也就是说,join会使延迟检索失效。


  1-14-1.load实现lazy延迟加载:
   1)load()加载对象时,采用延迟加载策略
 2)为了防止no session异常,在使用加载代理对象之前,调用Hibernate.initialize()方法对代理对象进行修改,会动态的修改代理字节码对象,
   用到的是cglib以及asm相关jar包。
                  
  1-14-1.一对一实现lazy延迟加载:
  org.hibernate.LazyInitializationException: could not initialize proxy - no Session
 
 1)主表不能实现懒加载!!!
    Class Task4:自己体会一下主表对象尝试对和其关联的子表对象延迟加载。


 2)只能在子表中实现对主表对象的懒加载(在子表映射文件中的配置要求有三:
1.lazy != false
2.constrained = true
3.fetch = select
                     )。
    主表映射文件配置:
    <class name="Country" table="countries" >
<id name="counId" column="cId" type="java.lang.Integer">
<generator class="sequence" >
                <param name="sequence">seq_cid</param>
        </generator>
</id>
<property name="counName" column="cName" type="java.lang.String"/>
<property name="counNumber" column="cNumber" type="java.lang.Integer"/>
<property name="counArea" column="cArea" type="java.lang.Double"/>
<one-to-one name="captial"  class="com.hd.oldboy.entity.Captial" ></one-to-one>

    </class>
    子表映射文件配置:
    <class name="Captial" table="captials" >
<id name="capId" column="capId" type="java.lang.Integer">
<generator class="foreign" >
                <param name="property">country</param>
        </generator>
</id>
<property name="capName" column="capName" type="java.lang.String"/>
<one-to-one name="country" lazy="proxy" class="com.hd.oldboy.entity.Country" constrained="true" > </one-to-one>
    </class>
  1-14-3.一对多和多对一实现lazy延迟加载:


  1)一对多关联的查询策略时:
    lazy属性为false;表示立即加载
    Eg:设置<set>元素的lazy属性为false,表示在加载部门的同时立即加载员工,双方的SQL命令都会被执行。


    // 获取Session对象
    Session session = HibernateUtil.currentSession();
    // 如果通过load方式加载Dept对象
    Dept dept=(Dept)session.load(Dept.class, 12);


  2)一对多关联的查询策略时:
    lazy属性为true,表示延迟加载。
    Eg:如下,在加载Dept对象的时候,就不会再去加载Emp对象,而且只会发出一条sql,这条sql就是指检索部门的信息
    // 获取Session对象
    Session session = HibernateUtil.currentSession();
    // 如果通过load方式加载Dept对象
    Dept dept=(Dept)session.load(Dept.class, 12);


  3)lazy属性为extra,表示增强延迟加载。
    其实增强延迟加载策略与一般的延迟加载策略lazy="true"非常相似。他们主要区别在于,我们看到这个名词增强延迟加载,
    个策略能在进一步的帮我延迟加载这个对象,也就是代理对象的初始化时机。例如:几乎要检索多方的信息了,如果是获得
    多方的个数信息,此时,还是不加载多方对象,只是执行一个检索个数的SQL命令而已,除非到了要用到集合中具体属性值。


    Eg:Emp和Dept之间的关系,在执行dept.getEmps().size()时,不会执行检索员工的语句,从而更加延迟检索
将会执行一个类似于:select count(*) from emp ...;


    // 获取Session对象
            Session session = HibernateUtil.currentSession();
             // 如果通过load方式加载Dept对象
             Dept dept=(Dept)session.load(Dept.class, 12);
             //拿该部门下的员工的人数:也就是集合的大小
             dept.getEmps().size();
  4)多对一关联的查询策略:
    lazy属性为proxy,表示代理延迟加载,在加载延迟加载的对象时,先获得是代理对象
             Eg:在加载Emp对象的时候会发出sql去查询数据库,但是在获取Dept对象的时候延迟加载了,所以不会发出sql
    // 获取Session对象
    Session session = HibernateUtil.currentSession();
             // 如果通过load方式加载Dept对象
             Emp emp=(Emp)session.get(Emp.class, 1);


             //获取Dept对象,因为此时的配置文件lazy是proxy,所以是代理对象
             Dept dept=emp.getDept();


  5)多对一关联的查询策略: 在<many-to-one>元素中配置lazy属性为no-proxy,表示无代理延迟加载
    Eg:
    // 获取Session对象
    Session session = HibernateUtil.currentSession();
             // 如果通过load方式加载Dept对象
             Emp emp=(Emp)session.get(Emp.class, 1);


             //获取Dept对象,因为此时的配置文件lazy是proxy,所以是代理对象
             Dept dept=emp.getDept();


    此程序在加载的Emp对象dept属性为NULL,当程序运行到第3行的时候将触发Hibernate执行查询Dept表的select语句,
    从而加载Dept对象,由此可见,当lazy属性为proxy时,可以延长延迟加载Dept代理对象的时间,而lazy属性为no-proxy时,
    则可以避免使用由Hibernate提供的Dept代理类实例,是Hibernate对程序提供更加透明的持久化服务。


   6)多对一关联的查询策略: 
     首先要设置<many-to-one>节点的lazy属性为false,表示立即加载
     Eg:EMP以及DEPT都会立即加载,发出SQL命令。
     // 获取Session对象
              Session session = HibernateUtil.currentSession();
              // 如果通过load方式加载Dept对象
              Emp emp=(Emp)session.get(Emp.class, 1);


              //获取Dept对象,因为此时的配置文件lazy是false,所以是实际对象
              Dept dept=emp.getDept();
      1-15.对象级级联操作
  1-15-1.一对多关系时,在many方添加数据:
  1-15-2.一对多关系时,在many方删除数据:
  1-15-3.修改一对多关系中实体对象间的关联关系:
  1-15-4.在一对多关系中的一方删除数据
  1-15-5.多对多关系操作:
  
      1-16.二级缓存的应用:对应于sessionFactory,同一个sessionFactory对象是同一个二级缓存。


  检索数据顺序:先看session(一级缓存)-->二级缓存-->查数据库


  缓存暂时存储,目的都是希望减少直接访问数据库的次数。
  一级缓存:就是session。
  二级缓存适用范围:一般都是一些不怎么频繁修改的数据、很少并发业务。
           二级缓存对应的空间:可以是内存也可以是硬盘。
  Hibernate中的二级缓存,往往通过插件实现。
  插件列表:


  组件 Provider类 类型 集群 查询缓存
  Hashtable org.hibernate.cache.HashtableCacheProvider 内存 不支持 支持
  EHCache org.hibernate.cache.EhCacheProvider 内存,硬盘 最新支持 支持
  OSCache org.hibernate.cache.OSCacheProvider 内存,硬盘 不支持 支持
  SwarmCache org.hibernate.cache.SwarmCacheProvider 集群 支持 不支持
  JBoss TreeCache org.hibernate.cache.TreeCacheProvider 集群 支持 支持
  怎么用:
  1)在Hibernate.cfg.xml文件中,添加使用二级缓存的配置信息。
     a.disable the second-level cache
<property name="cache.use_second_level_cache">true</property>
      在hibernate.properties文件中有相关字段:
      ## disable the second-level cache
      #hibernate.cache.use_second_level_cache false
     b.enable the query cache
<property name="cache.use_query_cache">true</property>
     c.choose a cache implementation:


name=hibernate.cache.region.factory_class 
value=org.hibernate.cache.ehcache.EhCacheRegionFactory


<property name="cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
           2)将ehcache.xml添加到项目的src路径下,可以适当的修改配置
           3)修改Hibernate.cfg.xml文件,明确需要添加到二级缓存的对象:
     <class-cache usage="read-only" class="com.hd.oldboy.entity.Manager"/>
     ...
     usage:指定缓存策略,可选的策略包括:transactional,read-write,
   nonstrict-read-write或read-only
  4)在需要被放置到二级缓存的对象映射文件中,添加标记:
     <class name="Manager" table="manager" >
<cache usage="read-only"/>
...
     </class>


     create table manager(
       manaId varchar2(50) primary key,
       manaName varchar2(100) not null,
       manaPwd varchar2(20) not null
     );
     insert into manager values('Hiber0001','Tiger','123');
      1-17.inverse: true和false,true意味着控制权的移交,比如:客户对订单,在一对多的一方
                    往往用set或bag实现关联,在其中可以添加inverse属性,体现对象间的关系,
   控制权交给多方对象。
      1-18.cascade:级联操作,也是有关联关系的一种属性设定,可以取值:all、delete、save-update
  删除操作,当删除客户时,会一并删除相关的订单。
           
   

猜你喜欢

转载自blog.csdn.net/aa15237104245/article/details/80469061