MyBatis 教程

👉 所有文章
文章列表 准备工作 回顾 JDBC 数据准备 查找id为1的用户信息 自定义连接池 不用MyBatis配置文件 查询密码为123的所有用户 如果Bean中成员变量和表中字段命名不一致 更多查询用户的方式 对查询结果排序 日志 添加、删除、修改数据 事务 动态SQL 一对一和一对多的实现 一对一和一对多的延迟加载 多对多的实现 分页查询 把SQL写在注解中 自动生成Mapper代码和映射XML mybatis generator 生成 select for update mybatis generator 支持数据版本号

MyBatis: 一对一和一对多的延迟加载


一对一和一对多的实现 我们了解了 mybatis 如何实现一对一和一对多,它的实现方案是通过写一个SQL取出两张表结合在一起的所有数据,然后mybatis稍作处理进行返回。还有一种实现方案是,写两个单独的 SQL ,通过id等业务字段进行关联,然后分别执行,得到最终结果。这种方案,还有一个优势,就是支持延迟加载。

本节示例代码在 mybatis-demo-013 ,基于一对一和一对多的实现 中的示例 mybatis-demo-012

数据准备

数据准备

user表和blog表的默认内容如下:

mysql> select * from user;
+----+--------+----------------+----------+
| id | name   | email          | password |
+----+--------+----------------+----------+
|  1 | letian | letian@111.com | 123      |
|  2 | xiaosi | xiaosi@111.com | 123      |
+----+--------+----------------+----------+

mysql> select * from blog;
+----+----------+---------------+--------------+
| id | owner_id | title         | content      |
+----+----------+---------------+--------------+
|  1 |        1 | 标题1         | 文本1        |
|  2 |        1 | 标题2         | 文本2        |
|  3 |        1 | 标题3         | 文本3        |
|  4 |        1 | 标题4         | 文本4        |
|  5 |        1 | 标题5         | 文本5        |
|  6 |        2 | 标题21        | 文本21       |
|  7 |        1 | 你好, World   | 你好, 😆       |
+----+----------+---------------+--------------+

项目结构

使用 IDEA 创建 gradle 项目,最终结构如下:

根据id查询博客及其所属用户信息

在 BlogMapper 接口中新增方法:

Blog findById(Long id);

在 BlogMapper.xml 中增加映射:

<resultMap id="blogResult" type="bean.Blog">
    <result property="id" column="blog_id"/>
    <result property="ownerId" column="user_id"/>
    <result property="title" column="blog_title"/>
    <result property="content" column="blog_content"/>

    <association property="user"
                 javaType="bean.User"
                 select="findOwnerOfBlog"
                 column="user_id" />

</resultMap>

<resultMap id="userResult" type="bean.User">
    <result property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <result property="email" column="user_email"/>
    <result property="password" column="user_password"/>
</resultMap>

<select id="findById" parameterType="Long" resultMap="blogResult" resultType="bean.Blog">
    SELECT
        id AS blog_id,
        id AS user_id,
        title AS blog_title,
        content AS blog_content
    FROM
        blog
    WHERE
        id = #{id};
</select>

<select id="findOwnerOfBlog"  parameterType="int"  resultMap="userResult" resultType="bean.User">
    SELECT
        id user_id,
        name user_name,
        email user_email,
        password user_password
    FROM
        user
    WHERE
        id=#{user_id};
</select>

findById 方法是和 <select id="findById"></select>对应的。 <select id="findById"></select> 的SQL 只是从 blog表中读取数据,它的resultMap属性值是blogResult,对应<resultMap id="blogResult"></resultMap>。而<resultMap id="blogResult"></resultMap>中的<association>使用了selectcolumn属性:

<association property="user"
                javaType="bean.User"
                select="findOwnerOfBlog"
                column="user_id" />

selecct对应的值是findOwnerOfBlog,意思是找<select id="findOwnerOfBlog"><select>column的值是user_id,意思是将user_id 的值传到<select id="findOwnerOfBlog"><select>中。

在 Main 类中编写示例代码:

@Test
public void test_03() throws IOException {
    SqlSession sqlSession = getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Blog blog = blogMapper.findById(1L);
    log.info("id:{}, title:{}, content:{}", blog.getId(), blog.getTitle(), blog.getContent());
    log.info("user: {}", blog.getUser());
}

执行结果:

DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 278934944.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@10a035a0]
DEBUG [main] - ==>  Preparing: SELECT id AS blog_id, id AS user_id, title AS blog_title, content AS blog_content FROM blog WHERE id = ?; 
DEBUG [main] - ==> Parameters: 1(Long)
DEBUG [main] - ====>  Preparing: SELECT id user_id, name user_name, email user_email, password user_password FROM user WHERE id=?; 
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <====      Total: 1
DEBUG [main] - <==      Total: 1
 INFO [main] - id:1, title:标题1, content:文本1
 INFO [main] - user: User(id=1, name=letian, email=letian@111.com, password=123, blogs=null)

可以看到两个SQL依次执行。

如何设置延迟加载

上面的示例中,在我们未获取 user 信息时,就已经把user信息取出来了。如何做到,用到再加载,也就是延迟加载呢?

很简单,在 mybatis-config.xml 加入:

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

再次执行上面的示例代码,结果是:

DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1209669119.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@481a15ff]
DEBUG [main] - ==>  Preparing: SELECT id AS blog_id, id AS user_id, title AS blog_title, content AS blog_content FROM blog WHERE id = ?; 
DEBUG [main] - ==> Parameters: 1(Long)
DEBUG [main] - <==      Total: 1
 INFO [main] - id:1, title:标题1, content:文本1
DEBUG [main] - ==>  Preparing: SELECT id user_id, name user_name, email user_email, password user_password FROM user WHERE id=?; 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
 INFO [main] - user: User(id=1, name=letian, email=letian@111.com, password=123, blogs=null)

注意,INFO [main] - id:1, title:标题1, content:文本1INFO [main] - user: User(id=1, name=letian, email=letian@111.com, password=123, blogs=null)之间,mybatis输出了查找用户信息的日志,这就是延迟加载。


( 本文完 )

文章目录