inverse属性

    inverse属性可以被设置到集合标签<set>上,表示在存储双向一对多关联映射的时候,存储的是那一方的关联引用。

    默认情况下,inverse“false”,所以,我们可以从的一端或者一端来维护两者之间的关系;

    如果我们设置inverse“true”,则只能通过一端来维护两者之间的关系inverse属性可以被用在一对多和多对多双向关联中;

   

    注意:inverse属性只是在将数据持久化到数据库的过程中发挥作用.

   

inversecascade

    * inverse是关联关系的控制方向

    * cascade是操作上的连锁反应

 

Cascade属性

 

用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操作,常用的cascade:none,all,save-update ,delete, lock,refresh,evict,replicate,persist,

    merge,delete-orphan(one-to-many)

一般对many-to-one,many-to-many不设置级联,在<one-to-one><one-to-many>中设置级联

 

lazy

能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getIdgetClass除外)hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将出现异常

 

lazy策略可以应用在:

    * <class>标签上,可以取值true/false

    * <property>标签上,可以取值true/false,需要类增强工具

    * <set> <list>集合标签上,可以取值true/false/extra

    * <one-to-one>,<many-to-one>单端关联上,可以取值false/proxy/noproxy

   

lazy的概念:

    1、在真正使用时发出查询语句加载相应的对象

 

    2hibernate支持lazy策略只有在session打开状态下才有效

   

    3hibernate(class)级别的lazy只对普通属性起作用,可以控制什么时候加载这些普通属性

 

hibernate在集合上的lazy策略:可以取值true/false/extra

 

<class>标签上配置的lazy不会影响到集合上的lazy特性

 

  true:默认取值,它的意思是只有在调用这个集合获取里面的元素对象时,才发出查询语句,加载其集合元素的数据

  false: 取消懒加载特性,即在加载对象的同时,就发出第二条查询语句加载其关联集合的数据

  extra: 一种比较聪明的懒加载策略,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据

 

 

hibernate在单端关联上的lazy策略:可以取值 false/proxy/noproxy

 

    false: 取消懒加载策略,即在加载对象的同时,发出查询语句,加载其关联对象

    proxy: 这是hibernate对单端关联的默认懒加载策略,即只有在调用到其关联对象的方法的时候才真正发出查询语句查询其对象数据,其关联对象是代理类

    no-proxy:这种懒加载特性需要对类进行增强,使用no-proxy,其关联对象不是代理类

 

注意:class标签上配置的lazy属性不会影响到关联对象!!!

 

<many-to-one name="Group" column="groupid" cascade="save-update" lazy="false"/>

many-to-one标签上的lazy属性默认是proxy

 

fetch

fetch=join”,这就是使用了预先抓取策略,也就是针对关联的对象的加载策略,在使用到关联对象的信息时会再发送sql语句,如果不使用fetch=join”,就会不使用表连接而是先查出一端的关联id再一条一条的发送sql语句查询到关联对象信息,使用了fetch=join”就会使用表连接将关联对象信息直接查寻出来的。fetch=lazy”这个是默认的设置。

 

 

Hibernate继承映射的第一种策略:每个类继承树对应一张表

所有类只建一个表,查寻效率比较高,但是会产生很多空间浪费,当子类中的非空约束,就不大适用了

1、理解如何映射

    因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。

    这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:

    * 父类用普通的<class>标签定义

    * 在父类中定义一个discriminator,即指定这个区分的字段的名称和类型

        如:<discriminator column=”XXX” type=”string”/>

 

    * 子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:

      Subclass标签的name属性是子类的全路径名

      Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值

      Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。

      subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。

      子类的其它属性,像普通类一样,定义在subclass标签的内部。

 

2、理解如何存储

    在存储数据的时候,hibernate会自动将鉴别字段的值插入到数据库中,在加载数据的时候,hibernate便能根据这个鉴别字段正确的加载对象

   

多态查询:在hibernate加载数据的时候能鉴别出真正的类型(instanceof

    get方法支持多态查询

    load方法只有把lazy设置为false才支持多态查询

    hql 支持多态查询

 

 

Hibernate继承映射的第二种策略:每个类对应一张表

 

1、如何映射

    这种策略是使用joined-subclass标签来定义子类的。父类、子类,每个类都对应一张数据库表。

    在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;

    在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。

    子类与父类,通过相同的主键值来关联。实现这种策略的时候,有如下步骤:

       父类用普通的<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标签的内部。

 

2、存储和多态查询参见策略一:每棵类继承树对应一张表

 

 

Hibernate继承映射第三种策略:每个具体类对应一张表(不常使用)

1、如何映射

这种策略是使用union-subclass标签来定义子类的。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,joined-subclass定义的子类的表,只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:

父类用普通<class>标签定义即可

子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:

Union-subclass标签不再需要包含key标签(与joined-subclass不同)

Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass标签中,添加extends属性,里面的值是父类的全路径名称。

子类的其它属性,像普通类一样,定义在Union-subclass标签的内部。这个时候,虽然在union-subclass里面定义的只有子类的属性,但是因为它继承了父类,所以,不需要定义其它的属性,在映射到数据库表的时候,依然包含了父类的所有属性的映射字段。

 

特别注意:在保存对象的时候,id不能重复(所以不能用自增方法生成主键)

 

2、存储和多态查询参见策略一:每棵类继承树对应一张表

 

 

component(组件映射)

   

    hibernate中,component是某个实体对象的逻辑组成部分

    它与实体的根本区别是:

       component是没有标识的,它是一个逻辑组成部分,完全从属于某个实体

      

    这样就在传统数据库上,实现了对象的细粒度划分,层次分明,实现了面向对象的领域划分

    Save只能保存实体类,component不是实体类,它只是实体类的一部分,所以不能保存

 

复合主键映射(联合主键)

 

    通常将复合主键相关属性,单独抽取出来,建立一个独立的类

      * 必须实现序列化接口

      * 必须实现equalshashCode方法

 

    采用<composite-id>标签进行映射,其它属性采用<property>正常映射

 

集合映射

Set:

<set name="setValues" table="t_set_values">

        <key column="set_id"/>

        <element type="string" column="set_values"/>

    </set>

List: (有序,必须保存索引位置)

<list name="listValues" table="t_list_values">

        <key column="list_id"/>

        <list-index column="list_index"/>

        <element type="string" column="list_value"/>

    </list>

Array: (有序,必须保存索引位置)

<array name="arrayValues" table="t_array_values">

        <key column="array_id"/>

        <list-index column="array_index"/>

        <element type="string" column="array_value"/>

    </array>

Map:

<map name="mapvalues" table="t_map_values">

        <key column="map_id"/>

        <map-key type="string" column="map_key"/>

        <element type="string" column="map_value"/>

    </map>

 

悲观锁

LockMode.UPGRADE 修改锁,在get()方法中加上这个设置作为第三个参数。

LockMode.NONE 无锁机制

LockMode.READ 读取锁

LockMode.WRITE 写入锁,不能在程序中直接使用

LockMode.UPGRADE_NOWAIT Oracle 的特定实现,利用Oraclefor update nowait 子句实现加锁

还可以使用Session.lock() Query.setLockMode() Criteria.setLockMode()方法来设置锁

 

悲观锁的实现:通常依靠数据库提供的机制,在整个处理过程中,将数据处于锁定状态;

其他任何用户都不能读取和修改

例如:select * from t_user where name="张三" for update

 

 

乐观锁

    大多数基于数据版本(version)记录机制实现,一般通过在数据库表中增加一个version字段实现,读取数据时将版本号一同读出,之后更新时对版本号加1

    如果提交的数据<=数据库中当前版本号,则认为是过期数据,否则给予更新。

 

悲观锁和乐观锁主要解决并发问题