• Hibernate基础知识整理(三)


    继承映射

    Employee(id,name,age);

    Skiller  extends Employee {skill};

    Seller extends Employee{sell};

    一:一张表实现继承映射

    create table  Employee(id int primary key,name varchar(20),age date,skill varchar(20),sell varchar(20));

    映射文件Employee.hbm.xml相关配置:

    <class name="Employee">

      <id name="id">

        <generator class="native"/>

      </id>

      <property name="name"/>

      <property name="age"/>

    </class>

    添加<discriminator  column="type" type="int">     ——鉴别器,缺省类型是字符串类型,挨着id写  ,并用discriminator-value=""进行区分,如下:

    <class name="Employee"  discriminator-value="0">
    
      <id name="id">
    
        <generator class="native"/>
    
      </id>
    
      <discriminator  column="type" type="int">
    
      <property name="name"/>
    
      <property name="age"/>
    
      <subclass name="Skiller" discriminator-value="1">
    
        <property name="skill"/>
    
      </subclass>
    
      <subclass name="Seller" discriminator-value="2">
    
        <property name="sell"/>
    
      </subclass>
    
    </class>

    这种配置效率较高,但是再增加子类,就必须再增加字段,并且不能设置多出来的字段为不为空;

    二:每一个子类一张表,通过外键关联

    Employee(id,name,age);

    Skiller  extends Employee {skill};

    Seller extends Employee{sell};

    表:

    create table employee(id int primary key,name varchar(20),age date);

    create table skiller(employee_id int primary key,skill varchar(20),foreign key (employee_id) references employee(id));

    create table seller(employee_id int primary key,sell varchar(20),foreign key (employee_id) references employee(id));

     映射Employee.hbm.xml文件相关配置:

    <class name="Employee">

      <id name="id">

        <generator class="native"/>

      </id>

      <property name="name"/>

      <property name="age"/>

    </class>

    添加

    <joined-subclass name="Skiller" table="skiller"><!-- join表示数据库表中使用连接与子类关联 -->
    <key column="emp_id"/><!-- 连接使用的外键列 -->
    <property name="skill"/>
    </joined-subclass>     如下:
    <class name="Employee">
    
      <id name="id">
    
        <generator class="native"/>
    
      </id>
    
      <property name="name"/>
    
      <property name="age"/>
    
      <joined-subclass name="Skiller" table="skiller">
    
        <key column="emp_id">
    
        <property name="skill"/>
    
      </joined-subclass>
    
      <joined-subclass name="Seller" table="seller">
    
        <key column="emp_id">
    
        <property name="sell"/>
    
      </joined-subclass>
    
    </class>
    

      

    表结构合理,子类和主类差距比较大的时候使用。
    多态方式查询的话关联表过多效率低。不使用多态查询的话就比较优秀

    每个子类映射成一张表有如下步骤:
        父类用普通的<class>标签定义即可
        父类不再需要定义discriminator字段
        子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:
        Joined-subclass标签的name属性是子类的全路径名
        Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
        如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。
        Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),
        也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,需要在Joined-subclass
        标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。

     三:鉴别器和内连接相关联

    Employee(id,name,age);

    Skiller  extends Employee {skill};

    Seller extends Employee{sell};

    表:

    create table employee(id int primary key,name varchar(20),age date,skill varchar(20));

    create table seller(employee_id int primary key,sell varchar(20),foreign key (employee_id) references employee(id));

    适用情况:雇员中销售的字段比较多但是技术的字段比较少

    映射文件Employee.hbm.xml相关配置:

    <class name="Employee">

      <id name="id">

        <generator class="native"/>

      </id>

      <property name="name"/>

      <property name="age"/>

    </class>

    添加鉴别器和join如下:

    <class name="Employee" discriminator-value="0"> <!-- 鉴别属性值为0表示为普通雇员,注意:鉴别器的值如果不给的话,默认认为是类名的全名称 -->
    <id name="id" >
    <generator class="native"/>
    </id>
    
    <discriminator column="type" type="int"/>
    <!-- 鉴别器,缺省类型是字符串类型 ,鉴别器的位置放置在property前面-->
    <property name="name"/>
    <subclass name="Skiller" discriminator-value="1"> 
    <property name="skill"/>
    </subclass>
    <subclass name="Sales" discriminator-value="2">
    <join table="sales">
    <key column="emp_id"/>
    <property name="sell"/>
    </join>
    </subclass>
    </class>
    

      

    四:每一个类一张表,且每一个表中都具有完整信息,如果父类不是抽象的,也会有父类表
    <class name="Employee">
      <id name="id" >
        <generator class="hilo"/>
       </id>
      <property name="name"/>
      <union-subclass name="Skiller" table="skiller">    <!-- union表示结合的意思 -->
        <property name="skill"/>
        </union-subclass>
        <union-subclass name="Sales" table="sales">    <!-- union表示结合的意思 -->
           <property name="sell"/>
        </union-subclass>
    </class>
    

      注意:父类和子类表的id是不能重复的,所以我们的主键生成策略不能再时native或者identity这种自增长了。

    五:懒加载
      
    懒加载就是返回的其实是一个代理对象,该代理对象是你的domain对象的一个子类。在你使用到该对象的时候,hibernate才进行数据库的查询
    懒加载的对象在session关闭之后调用该属性会报错。no Session,无法访问数据库,解决方法:
    1、在session未关闭之前就调用一下该对象的属性,使得hibernate访问数据库,将代理对象中的对应值填充好。
    2、使用Hibernate.initialize(Object)方法实例化懒加载的对象,这样他就会查询数据库将该对象持久化。 
    one-to-one(元素)懒加载
    必须同时满足下面三个条件:
    (主表不能有constrained=true,所以主表没有懒加载)
    1、lazy属性不等于false
    2、constraint=true。有外键关联
    3、fetch=select 抓取方式为select
    多对一、一对多、多对多进行懒加载的要求:
    lazy属性不能为false,
    fetch为select
    六:hibernate中的缓存
    Hibernate的缓存分为一级缓存和二级缓存;
    一级缓存(session级别的缓存):hibernate默认缓存;非线程安全
    save、update、saveOrUpdate、load、get、list、iterate、lock这些方法都会将对象存入session一级缓存中;
    一级缓存不能控制缓存的数量,所以请注意大批量操作数据时可能造成内存溢出,可以用evict,clear方法清除缓存中的指定对象和清空缓存。
    二级缓存:可插拔的缓存,SessionFactory级别,线程安全
    配置缓存插件的步骤:
    1、hibernate中开启二级缓存。
    在hibernate.cfg.xml中配置<property name="cache.use_second_level_cache">true</property>。这个属性在缺省状态下为true,也就是默认hibernate是打开二级缓存的
    2、指定二级缓存插件的提供者。这里我使用的是OSCache
    <property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
    使用该缓存插件的时候注意你有没有导入该缓存包
    src下面加入一个oscache.properties文件,然后在该文件中配置了os缓存的一些信息;
    3.加入你需要对user类的对象进行缓存,当然缓存的额是持久化对象。可以在hibernate.cfg.xml中配置:
    <class-cache usage="read-only" class="cn.itcast.domain.User"/>
    也可以在bean的映射文件中配置,比如:
    <class name="User">
    <cache usage="read-only"/>
    其中usage属性是表示缓存的级别:
    read-only则表示缓存的东西不会发生改变,比如缓存省市这种东西的时候就可以使用这个级别的缓存。如果缓存的对象发生了改变就会报错
    read-write表示允许对缓存的对象进行读写操作,而且具有很好的并发性,缓存的内容基本不会出现问题
    nonstrict-read-write表示允许对缓存的对象进行读写操作,并发要求不高,可能出现一些错误数据。在你允许一些缓存问题的情况下使用,比如评论。
    查看一些hibernate的状态:
    可以在配置文件中打开统计信息,然后借助统计信息,得到你需要的信息。
    <property name="hibernate.generate_statistics">true</property> 

    hibernate进行数据的查询,首先在一级缓存查找,然后如果没有在二级缓存查找,如果还没有再往数据库查找

    将信息放入二级缓存的方法:

    
    

    save、update、saveOrUpdate、list、iterator、get、load、以及Query、Critria都会填充二级缓存,查询数据时session的iterator、get、load可以从缓存中读取数据

    
    

    注意:session中的save方法不适合native生成方式的主键,也就是说native生成方式的主键使用save方法可能不会存入缓存

    
    

    Query、Criteria(查询缓存)由于命中率低,所以hibernate缺省是关闭修改hibernate.cfg.xml中的property:

    
    

    <property name="cache.use_query_cache">true</property>才能打开查询缓存

    
    

    并且query和Criteria存储结果入二级缓存中需要使用query.setCacheable(true),Criteria.setCacheable(true)结果才能存入二级缓存

    
    

    SessionFactory中使用evit()或者evitXXX()清除缓存内容

    
    

    统计信息打开generate_statics用sessionFactory.getStatics()获取统计信息

     
  • 相关阅读:
    如何解决快应用堆栈溢出问题
    华为携手Work Shift Calendar (Shifter),将工作效率提升至更高水平
    教你如何实现长按图片保存到相册
    【DTM】HUAWEI Ads与DTM网页转化追踪(二)
    map组件如何展示marker的callout气泡
    【DTM】HUAWEI Ads与DTM网页转化追踪(一)
    “碰一碰”版本的蓝牙键盘,来啦!
    ES-密码设置及JAVA应用
    ES--集群搭建及原理
    ES--ELK搭建(ElasticSearch、Logstash、Kibana)
  • 原文地址:https://www.cnblogs.com/xiaoweigangwan/p/7815783.html
Copyright © 2020-2023  润新知