zoukankan      html  css  js  c++  java
  • 一步步认识NHibernate的延迟加载

          说到NHibernate(以下简称NH),想必大家都非常熟悉了,他是.net中ORM的利器,算是非常强大,且使用的用户也非常多,那么一个强大的第三方框架,所包含的功能特性那肯定是很丰富的,其中就包括XML映射配置、延迟加载、HQL查询、原声SQL查询,什么二级缓存等等,总之入门是要有一定的时间和准备的,这里就把我所认识的“延迟”加载进行说明。

          什么是NH的延迟加载呢,延迟加载是Nh的一种机制,主要是解决不必要的查询对资源的浪费,只有当数据真正调用时才加载,而不会对数据进行提前加载造成资源的浪费,这句话是从网上看到的,其实就是这个意思,那么用我们程序的语言讲是这样的:就是有一个class,里面包含一个属性,属性的类型是一个集合(如IList<Role>),当我们需要加载一个对象(或者说记录吧)的时候,但又不想使用里面的那个集合属性,这个时候我们就可以使用延迟加载了,当一个类的集合使用了延迟加载的时候,那么只有使用这个集合的时候,NH才会发出SQL到数据库查询这个对象,这个就是传说中的延迟加载吧【个人理解】。

          上面说的“加载对象”和“使用集合属性”又是怎么理解呢?我们先说下Nh的加载对象的方法吧,总所周知,一个是Get,一个是Load,那么,他们又有什么区别呢,这个还是有点复杂的。

    1. 对于get方法,NH会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查询数据库,数据库中没有就返回null

    2. load方法加载实体对象的时候,根据映射文件上类级别的lazy属性的配置(默认为true),分情况讨论:

    (1)若为true,则首先在Session缓存中查找,看看该id对应的对象是否存在,不存在则使用延迟加载,返回实体的代理类对象(该代理类为实体类的子类,由CGLIB动态生成)。等到具体使用该对象(除获取OID以外)的时候,再查询二级缓存和数据库,若仍没发现符合条件的记录,则会抛出一个ObjectNotFoundException

    (2)若为false,就跟get方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个ObjectNotFoundException

    以上转载http://blog.csdn.net/lenotang/article/details/2595349

    我们再说一下“使用集合属性”,这个一般就两种情况,一种是通过调用session的Get或者Load方法加载对象,另外一种是在第一种的前提下,使用对象的一个属性,也就是点【.】一下。

    下面就用代码开讲解“延迟加载”,“使用集合属性”。

    实体类映射文件(根据类映射,也可以猜到具体的实体类是怎么样的,这里就不上传了):

    View Code
     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="LBC.Model" assembly="LBC.Model">
     3   <class name="LBC.Model.User, LBC.Model" table="T_User" lazy="true">
     4     <id name="UserID" column="UserID">
     5       <generator class="assigned" />
     6     </id>
     7     <property name="UserName" column="UserName" />
     8     <property name="Password" column="Password" />
     9     <bag name="Roles" cascade="all" inverse="true" lazy="true" table="T_UserRole">
    11       <key column="UserID"></key>
    12       <many-to-many class="Role" column="RoleID" not-found="ignore"/>
    13     </bag>
    14   </class>
    19 </hibernate-mapping>
    View Code
     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="LBC.Model" assembly="LBC.Model">
     3   <class name="LBC.Model.Role, LBC.Model" table="T_Role" lazy="true">
     4     <id name="RoleID" column="RoleID">
     5       <generator class="identity" />
     6     </id>
     7     <property name="RoleName" column="RoleName" />
     8     <property name="Description" column="Description" />
     9     <property name="Expired" column="Expired" />
    10     <bag name="Users" cascade="all" inverse="true" lazy="true" table="T_UserRole">
    11       <key column="RoleID"></key>
    12       <many-to-many class="User" not-found="ignore" column="UserID"/>
    13     </bag>
    14   </class>
    15 </hibernate-mapping>

    1、我们把User和Role这两个类级别的lazy修改为false,并使用session的Get方法加载一个User对象

    这个时候,NH只生成了一条sql,说明没有去加载Roles集合【这样可以说明NH的Get对于集合属性是可以延迟加载的吧】

    这里在加载User对象后去访问Roles集合属性,要把鼠标移动到roles变量那边,这里没有截图下来

    很明显,这里NH发出了两条sql语句,一条是查询User对象,一条是查询Roles集合的

    那么,把User和Role类级别的lazy修改为true又会是怎么样的呢,结果是跟false一样,这里就不做说明了

    2、我们把User和Role这两个类级别的lazy修改为false,且User映射文件的bag里面的lazy也修改为false,并使用session的Get方法加载一个User对象

    这个时候,NH生成了两条sql语句,跟上面的情况(加载后去访问集合属性)是一样的。那么我们再把类级别的lazy修改为false会是什么结果呢,当然,结果还是一样的,那么通过以上的描述,我们可以知道,NH在使用session的Get加载对象的时候,也是可以延迟加载的,至少是我们在没有去访问集合属性的时候NH是不会生成sql的,这个应该就是我们说的延迟的道理【这里说的延迟仅对于集合属性,而非类本身】。

    3、我们把User和Role这两个类级别的lazy修改为false,且User映射文件的bag里面的lazy修改为true,并使用session的Load方法加载一个User对象

     我们可以看到,使用Load加载,且类级别lazy为false,bag的lazy为true的时候,NH只生成一条sql

    4、我们把User和Role这两个类级别的lazy修改为true,且User映射文件的bag里面的lazy修改为true,并使用session的Load方法加载一个User对象

    喔,NH竟然一条sql都没有生成,真实大快人心啊。当我们把鼠标移动到user变量的时候,NH就会生成加载User对象的sql,如果再访问user的Roles属性,那么又会生成一条加载roles的sql。

     

    最后,我们来个大总结吧:

    1、NH的延迟加载的意思就是:你访问了属性(就是点一个属性出来,除了ID之外)就生成sql到数据库加载

    2、NH的在延迟加载有2个方面,一个是延迟加载类的;另外一个是延迟加载集合的

    3、NH的类延迟加载仅对于使用session的Load方法时才有效【如果使用Get的话,不管类级别的lazy怎么配置,始终会生成一条加载类本身的sql】

    4、NH的集合延迟加载,对于session的Get和Load方法都是有效的

    5、如果把类级别的lazy设置为false,那么不管是Get还是Load都发生成一条加载类本身的sql

    6、如果把类级别的lazy设置为true,那么Get会生成加载类本身的sql,而Load不会

  • 相关阅读:
    IntelliJ IDEA 快捷键大全
    springboot整合jsp 遇到的问题
    mysql数据库中某字段一部分乱码
    Spring-boot整合Redis,遇到的问题
    遍历对象和数组的forEach函数
    获取随机数,要求长度一致的字符串格式
    获取yyyy-mm-dd格式的日期
    JS对象常用API
    数组常用API
    JS中异步和单线程
  • 原文地址:https://www.cnblogs.com/liubiaocai/p/2173991.html
Copyright © 2011-2022 走看看