精华内容
下载资源
问答
  • mybatis延迟加载

    2017-12-29 15:00:23
    mybatis延迟加载

    什么是延迟加载

    • resultMap可实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
    • 延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
    • 如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

    使用association实现延迟加载

    • 先查询订单信息这里写图片描述这里写图片描述
      • column属性指定要将查询的结果的哪个字段的值,作为参数传递给下一表查询
    • 根据上面查询的结果查询用户信息这里写图片描述
    • 打开延迟加载开关这里写图片描述
      • lazyLoadingEnabled:设置懒加载,默认为false。如果为false:则所有相关联的都会被初始化加载。
      • aggressiveLazyLoading:默认为true。当设置为true时,懒加载的对象可能被任何懒属性全部加载;否则,每个属性按需加载。
    • 使用collection实现延迟加载,同理
    展开全文
  • Mybatis延迟加载

    2020-10-24 15:52:09
    Mybatis延迟加载延迟加载如何实现延迟加载一对一方式延迟加载一对多方式延迟加载 延迟加载 延迟加载:真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)。 优点:先从单表查询,需要时再从关联表去...

    延迟加载

    • 延迟加载:真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)。

    优点:先从单表查询,需要时再从关联表去关联查询,大大提高了数据库的性能,因为查询单表要比关联查询多张表的速度快的多。

    • 立即加载:不管用不用,只要一调用方法,马上发起查询。

    如何实现延迟加载

    
     - 我们在进行多表的操作时,在配置文件中通过resultMap实现一对多、
      多对一和一对一关系的操作,主要是通过association、collection
      具备延迟加载功能。
    
    

    一对一方式延迟加载

    1. 第一步:在SqlMapConfig.xml(配置文件)中配置延迟加载的全局开关,可取Mybatis官网参考配置
      在这里插入图片描述
      在这里插入图片描述
     <!-- 开启Mybatis支持延迟加载-->
        <settings>
            <setting name="lazyLoadingEnabled" value="true"></setting>
            <setting name="aggressiveLazyLoading" value="false"></setting><!--在3.4.1版本及其之后不用再写aggressiveLazyLoading 因为其默认值为false-->
        </settings>
    
    1. 第二步:在resultMap中设置association .
    <!--定义封装account和user的resultMap-->
        <resultMap id="accountUserMap" type="Account">
            <!--前三只能保证account的数据封装-->
            <id property="id" column="id"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
            <!--select指定的内容,查询用户的唯一标识(namespace+id)
            column属性指定的内容:用户根据id查询时,所需要的参数的值(account表的外键)-->
            <association property="user" column="uid" select="com.itheima.dao.IUserDao.findById"></association>
        </resultMap>
    

    测试:
    在这里插入图片描述
    延迟加载成功!
    在这里插入图片描述

    一对多方式延迟加载

       <!--配置user对象中的的accounts集合的映射-->
            <collection property="accounts" ofType="com.itheima.domain.Account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id">
            </collection>
    
    展开全文
  • MyBatis延迟加载

    千次阅读 2018-10-19 19:52:27
    MyBatis源码解读之延迟加载 目的 本文主要解读MyBatis 延迟加载实现原理 延迟加载如何使用 Setting 参数配置 设置参数描述有效值默认值lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载...

    MyBatis源码解读之延迟加载

    1. 目的
      本文主要解读MyBatis 延迟加载实现原理
    2. 延迟加载如何使用
      Setting 参数配置
      设置参数描述有效值默认值lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。true、falsefalseaggressiveLazyLoading当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).true、falsefalse (true in ≤3.4.1)lazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashCode,toString
      配置

    Mapper 配置 3. select * from users where id = #{id} User 实体对象 public class User implements Cloneable { private Integer id; private String name; private User lazy1; private User lazy2; private List lazy3; public int setterCounter;

    省略…
    }
    执行解析:
    调用getUser查询数据,从查询结果集解析数据到User对象,当数据解析到lazy1,lazy2,lazy3判断需要执行关联查询
    lazyLoadingEnabled=true,将创建lazy1,lazy2,lazy3对应的Proxy延迟执行对象lazyLoader,并保存
    当逻辑触发lazyLoadTriggerMethods 对应的方法(equals,clone,hashCode,toString)则执行延迟加载
    如果aggressiveLazyLoading=true,只要触发到对象任何的方法,就会立即加载所有属性的加载
    3. 延迟加载原理实现
    延迟加载主要是通过动态代理的形式实现,通过代理拦截到指定方法,执行数据加载。
    MyBatis延迟加载主要使用:Javassist,Cglib实现,类图展示:

    1. 延迟加载源码解析
      Setting 配置加载:
      public class Configuration {
      /** aggressiveLazyLoading:
    • 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).
    • 默认为true
    • /
      protected boolean aggressiveLazyLoading;
      /
      *
    • 延迟加载触发方法
      /
      protected Set lazyLoadTriggerMethods = new HashSet(Arrays.asList(new String[] { “equals”, “clone”, “hashCode”, “toString” }));
      /
      * 是否开启延迟加载 */
      protected boolean lazyLoadingEnabled = false;

    /**

    • 默认使用Javassist代理工厂
    • @param proxyFactory
      */
      public void setProxyFactory(ProxyFactory proxyFactory) {
      if (proxyFactory == null) {
      proxyFactory = new JavassistProxyFactory();
      }
      this.proxyFactory = proxyFactory;
      }

    //省略…
    }
    延迟加载代理对象创建
    DefaultResultSetHandler
    //#mark 创建结果对象
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList

    • 创建代理
    • @param target 目标结果对象
    • @param lazyLoader 延迟加载对象
    • @param configuration 配置
    • @param objectFactory 对象工厂
    • @param constructorArgTypes 构造参数类型
    • @param constructorArgs 构造参数值
    • @return
      */
      Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List constructorArgs);
      }
      JavasisstProxyFactory实现
      public class JavassistProxyFactory implements org.apache.ibatis.executor.loader.ProxyFactory {

    /**

    • 接口实现
    • @param target 目标结果对象
    • @param lazyLoader 延迟加载对象
    • @param configuration 配置
    • @param objectFactory 对象工厂
    • @param constructorArgTypes 构造参数类型
    • @param constructorArgs 构造参数值
    • @return
      */
      @Override
      public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List constructorArgs) {
      return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
      }
      //省略…

    /**

    • 代理对象实现,核心逻辑执行
      */
      private static class EnhancedResultObjectProxyImpl implements MethodHandler {

    /**

    • 创建代理对象
    • @param type
    • @param callback
    • @param constructorArgTypes
    • @param constructorArgs
    • @return
      */
      static Object crateProxy(Class<?> type, MethodHandler callback, List

    /**

    • 代理对象执行
    • @param enhanced 原对象
    • @param method 原对象方法
    • @param methodProxy 代理方法
    • @param args 方法参数
    • @return
    • @throws Throwable
      */
      @Override
      public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
      final String methodName = method.getName();
      try {
      synchronized (lazyLoader) {
      if (WRITE_REPLACE_METHOD.equals(methodName)) {
      //忽略暂未找到具体作用
      Object original;
      if (constructorArgTypes.isEmpty()) {
      original = objectFactory.create(type);
      } else {
      original = objectFactory.create(type, constructorArgTypes, constructorArgs);
      }
      PropertyCopier.copyBeanProperties(type, enhanced, original);
      if (lazyLoader.size() > 0) {
      return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
      } else {
      return original;
      }
      } else {
      //延迟加载数量大于0
      if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
      //aggressive 一次加载性所有需要要延迟加载属性或者包含触发延迟加载方法
      if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
      log.debug("==> laze lod trigger method:" + methodName + “,proxy method:” + methodProxy.getName() + " class:" + enhanced.getClass());
      //一次全部加载
      lazyLoader.loadAll();
      } else if (PropertyNamer.isSetter(methodName)) {
      //判断是否为set方法,set方法不需要延迟加载
      final String property = PropertyNamer.methodToProperty(methodName);
      lazyLoader.remove(property);
      } else if (PropertyNamer.isGetter(methodName)) {
      final String property = PropertyNamer.methodToProperty(methodName);
      if (lazyLoader.hasLoader(property)) {
      //延迟加载单个属性
      lazyLoader.load(property);
      log.debug(“load one :” + methodName);
      }
      }
      }
      }
      }
      return methodProxy.invoke(enhanced, args);
      } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
      }
      }
      }
    1. 注意事项
      1.IDEA调试问题 当配置aggressiveLazyLoading=true,在使用IDEA进行调试的时候,如果断点打到代理执行逻辑当中,你会发现延迟加载的代码永远都不能进入,总是会被提前执行。 主要产生的原因在aggressiveLazyLoading,因为在调试的时候,IDEA的Debuger窗体中已经触发了延迟加载对象的方法。
      如图:调试还未进入lazyLoader.loadAll(); 实际日志已经显示延迟加载已经完成,代码与日志通过颜色区分。
    展开全文
  • mybatis 延迟加载

    2019-01-15 10:51:58
    mybatis 延迟加载 什么是延迟加载 延迟加载又叫懒加载,也叫按需加载,也就是说先加载主信息,需要的时候,再去加载从信息。代码中有查询语句,当执行到查询语句时,并不是马上去DB中查询,而是根据设置的延迟策略将...
        

    mybatis 延迟加载

    什么是延迟加载

    延迟加载又叫懒加载,也叫按需加载,也就是说先加载主信息,需要的时候,再去加载从信息。代码中有查询语句,当执行到查询语句时,并不是马上去DB中查询,而是根据设置的延迟策略将查询向后推迟。

    什么时候会执行延迟加载

    配置之后在对关联对象进行查询时使用延迟加载。

    延迟加载策略
    直接加载

    遇到代码中查询语句,马上到DB中执行select语句进行查询。(这种只能用于多表单独查询)

    侵入式延迟加载

    将关联对象的详情(具体数据,如id、name)侵入到主加载对象,作为主加载对象的详情的一部分出现。当要访问主加载对象的详情时才会查询主表,但由于关联对象详情作为主加载对象的详情一部分出现,所以这个查询不仅会查询主表,还会查询关联表。

    深度延迟加载

    将关联对象的详情(具体数据,如id、name)侵入到主加载对象,作为主加载对象的详情的一部分出现。当要访问主加载对象的详情时才会查询主表,但由于关联对象详情作为主加载对象的详情一部分出现,所以这个查询不仅会查询主表,还会查询关联表。

    使用延迟加载的目的

    减轻DB服务器的压力,因为我们延迟加载只有在用到需要的数据才会执行查询操作。

    配置
        <settings>
            <setting name ="aggressiveLazyLoading" value="false"/>
            <!--开启延迟加载-->
            <setting name="lazyLoadingEnabled" value="true"/>
        </settings>

    我们用关联查询来实现延迟加载,假设我们现在要查出用户和用户角色。

    首先我们在user中添加查询userVo的方法和xml。

    <!--userMapper.xml-->
    
    ....
    <resultMap id="BaseResultMap" type="com.redstar.basemapper.pojo.User">
            <id column="id" jdbcType="VARCHAR" property="id"/>
            <result column="name" jdbcType="VARCHAR" property="name"/>
            <result column="age" jdbcType="INTEGER" property="age"/>
            <result column="role_id" jdbcType="INTEGER" property="roleId"/>
        </resultMap>
        <resultMap id="userRoleMapSelect" type="com.redstar.basemapper.pojo.UserVo">
            <association property="user" resultMap="BaseResultMap"/>
            <association property="role" fetchType="lazy" column="{id=role_id}"
                         select="com.redstar.basemapper.dao.RoleMapper.getRoleById"/>
        </resultMap>
        <sql id="Base_Column_List">
        id, `name`, age, role_id
      </sql>
        <select id="getUserVo" resultMap="userRoleMapSelect">
          select * from user where id=#{userId}
        </select>
    ...
        
        
        
        <!--roleMapper.xml-->
    ...    
        <resultMap id="BaseResultMap" type="com.redstar.basemapper.pojo.Role">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="role_name" jdbcType="VARCHAR" property="roleName" />
      </resultMap>
      <sql id="Base_Column_List">
        id, role_name
      </sql>
      <select id="getRoleById" resultMap="BaseResultMap">
        select * from role where id=#{id}
      </select>
    ...  

    测试用例

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class BaseMapperApplicationTests {
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private RoleMapper roleMapper;
    
        @Test
        public void getUserVo() {
            System.out.println(userMapper.getUserVo("12312232"));
    //        System.out.println(userMapper.getUserById("12312232"));
    //        System.out.println(roleMapper.getRoleById(1));
    
        }
    
    
    }

    输出结果:

    UserVo{user=User [Hash = 1937575946, id=12312232, name=哇哈哈啊娃哈哈哇哈哈哈哈哈哈哈, age=48, roleId=1, serialVersionUID=1], role=Role [Hash = 317053574, id=1, roleName=admin, serialVersionUID=1]}
    注意
    许多对延迟加载原理不太熟悉的朋友会经常遇到一些莫名其妙的问题:有些时候延迟加载
    可以得到数据,有些时候延迟加载就会报错,为什么会出现这种情况呢?
    MyBatis 延迟加载是通过动态代理实现的,当调用配直为延迟加载的属性方法时, 动态代
    理的操作会被触发,这些额外的操作就是通过 MyBatis 的 SqlSessio口去执行嵌套 SQL 的 。
    由于在和某些框架集成时, SqlSession 的生命周期交给了框架来管理,因此当对象超出
    SqlSession 生命周期调用时,会由于链接关闭等问题而抛出异常 。 在和 Spring 集成时,要
    确保只能在 Service 层调用延迟加载的属性 。 当结果从 Service 层返回至 Controller 层时, 如果
    获取延迟加载的属性值,会因为 SqlSessio口已经关闭而抛出异常 。
    展开全文
  • MyBatis 延迟加载

    2019-09-27 10:13:36
    MyBatis中的延迟加载,也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。例如在进行一对多查询的时候,只查询出一方,当程序中需要多方的数据时,mybatis再发出sql语句进行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,462
精华内容 1,384
关键字:

mybatis延迟加载