Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

1 个回答

  • 美世美
    慢慢理解世界,慢慢更新自己。
    #### 支持延迟加载 MyBatis 支持延迟加载,但仅限于 `association` 关联对象和 `collection` 关联集合对象。 - **`association`**:一对一关联查询。 - **`collection`**:一对多关联查询。 #### 配置延迟加载 在 MyBatis 配置文件中,可以配置是否启用延迟加载: ```xml <settings> <setting name="lazyLoadingEnabled" value="true"/> </settings> ``` #### 延迟加载的实现原理 MyBatis 使用 CGLIB 创建目标对象的代理对象,实现延迟加载。当调用目标方法时,进入拦截器方法,延迟加载的具体实现过程如下: 1. **代理对象的创建** - MyBatis 使用 CGLIB 动态代理技术为 `association` 和 `collection` 创建代理对象。 2. **方法拦截** - 当调用目标对象的方法时,进入 CGLIB 的拦截器方法。 - **示例**:调用 `a.getB().getName()` 时,首先进入代理对象的拦截器方法。 3. **检查属性值** - 拦截器方法检查关联对象(如 `a.getB()`)是否为 `null`。 - 如果是 `null`,则说明关联对象尚未加载。 4. **发送查询** - 拦截器方法发送事先保存好的查询关联对象的 SQL 语句,查询关联对象。 - **示例**:查询 `B` 对象的 SQL 语句。 5. **设置属性值** - 查询结果返回后,调用目标对象的 setter 方法,将查询结果设置到目标对象的关联属性中。 - **示例**:调用 `a.setB(b)`,将查询到的 `B` 对象设置到 `a` 对象的 `b` 属性中。 6. **继续方法调用** - 设置完关联对象后,继续执行原始方法调用。 - **示例**:完成 `a.getB().getName()` 方法的调用。 ### 示例 假设有以下实体类: ```java public class A { private B b; // getters and setters } public class B { private String name; // getters and setters } ``` 在 MyBatis 的映射文件中配置延迟加载: ```xml <settings> <setting name="lazyLoadingEnabled" value="true"/> </settings> <resultMap id="aResultMap" type="A"> <association property="b" javaType="B" select="selectBById" column="b_id"/> </resultMap> <select id="selectAById" resultMap="aResultMap"> SELECT id, b_id FROM A WHERE id = #{id} </select> <select id="selectBById" resultType="B"> SELECT id, name FROM B WHERE id = #{id} </select> ``` 调用示例: ```java SqlSession session = sqlSessionFactory.openSession(); A a = session.selectOne("selectAById", 1); System.out.println(a.getB().getName()); // 此时触发延迟加载 session.close(); ``` ### 总结 - **延迟加载的支持**:MyBatis 支持 `association`(一对一)和 `collection`(一对多)的延迟加载。 - **配置**:通过在 MyBatis 配置文件中设置 `lazyLoadingEnabled` 为 `true` 来启用延迟加载。 - **实现原理**: - 使用 CGLIB 创建目标对象的代理对象。 - 调用目标方法时,进入拦截器方法。 - 拦截器检查关联对象是否为 `null`。 - 如果为 `null`,则发送查询 SQL,查询关联对象。 - 将查询结果设置到目标对象的关联属性中。 - 继续执行原始方法调用。
    发布于 2024-07-26 00:33 •IP属地 安徽
    举报
    评论
    收藏