从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

    • Redis

    • Mybatis

      • Mybatis 介绍
      • Mybatis 入门案例
      • Mybatis 入门案例-注解
      • Mybatis 入门案例-实现类
      • Mybatis 内部执行原理概述
      • 实现一个微型的 Mybatis-配置文件版
      • 实现一个微型的 Mybatis-注解版
      • Mybatis 实现 CRUD
      • Mybatis 中传递对象参数
      • Mybatis 中的列名和属性名的映射
      • Mybatis 实现 DAO 层的开发
      • Mybatis 实现类的执行过程-查询方法
      • properties 标签的使用及细节
      • typeAliases 标签和 package 标签
      • Mybatis 连接池和事务
      • Mybatis 与 JNDI
      • Mybatis 中的动态 SQL
      • Mybatis 多表查询
      • Mybatis 中的多对多查询
      • Mybatis 的延迟加载
      • Mybatis 的缓存
      • Mybatis 的注解开发-CRUD
      • Mybatis 的注解开发-多表查询
        • 注解建立成员变量和列名的映射
        • 一对一查询
        • 一对多查询
        • 缓存的配置
        • 源码
    • Lucene

    • Elasticsearch

    • MQ

    • MyCat

    • Lombok

  • SpringMVC

  • SpringBoot

  • Java
  • 主流框架
  • Mybatis
2023-04-25
目录

Mybatis 的注解开发-多表查询

# 210.Mybatis 的注解开发-多表查询

来讲解更多使用注解完成开发的步骤。 ‍

# 注解建立成员变量和列名的映射

之前我们类的成员变量和数据库列名是一致的,所以不用映射;而使用注解也支持建立映射。

我们修改其成员变量的名字,和数据库列名不一致:

public class User implements Serializable {
    private Integer userId;
    private String userName;
    private String userAddress;
    private String userSex;
    private Date userBirthday;
}
1
2
3
4
5
6
7

注:自行生成 getter 和 setter。 ‍ 我们可以使用 Results 注解来完成映射。

@Select("select * from user")
@Results(value = {
        @Result(id=true, column = "id", property = "userId"),
        @Result(column = "username", property = "userName"),
        @Result(column = "address", property = "userAddress"),
        @Result(column = "sex", property = "userSex"),
        @Result(column = "birthday", property = "userBirthday")
})
List<User> findAll();
1
2
3
4
5
6
7
8
9

‍ 再次运行 findAll 方法,可以看到正常运行。 ‍ 那么其他 CRUD 注解还需要自己写一份 Results 注解吗?不用的,我们可以给 Result 定义一个 id,然后其他注解可以应用这个 ID:

@Select("select * from user")
@Results(id = "userMap", value = {
        @Result(id=true, column = "id", property = "userId"),
        @Result(column = "username", property = "userName"),
        @Result(column = "address", property = "userAddress"),
        @Result(column = "sex", property = "userSex"),
        @Result(column = "birthday", property = "userBirthday")
})
List<User> findAll();
1
2
3
4
5
6
7
8
9

‍ 其他注解就可以使用 ResultMap 来指定:注意 ResultMap 可以写多个,这里我们只用到了一个

@Select("select * from user where id=#{id}")
@ResultMap("userMap")
User findById(Integer id);
1
2
3

# 一对一查询

我们试着在查询账户的时候,同时查询用户信息,

新建 Account 类:

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
}
1
2
3
4
5

请读者自行生成 setter 和 getter。 ‍ 新增 IAccountDao.java 接口

public interface IAccountDao {
    @Select("select * from account")
    List<Account> findAll();
}
1
2
3
4

‍ 新建测试类 AccountAnnoTest:

@Test
public void testFindAll(){
    List<Account> accounts = iAccountDao.findAll();
    for(Account account : accounts){
        System.out.println(account);
    }
}
1
2
3
4
5
6
7

可以正常打印;

新增 User 成员变量:

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;

    // 多对一(在Mybatis称为一对一)的映射
    private User user;
}
1
2
3
4
5
6
7
8

‍ 修改 findAll 方法:

@Select("select * from account")
@Results(id = "accountMap", value = {
        @Result(id = true, column = "id", property = "id"),
        @Result(column = "uid", property = "uid"),
        @Result(column = "money", property = "money"),
        @Result(column = "uid", property = "user", one = @One(select = "com.peterjxl.dao.IUserDao.findById", fetchType= FetchType.EAGER) )
})
List<Account> findAll();
1
2
3
4
5
6
7
8

one 表示一对一查询,selet 属性则是根据某个方法来查询,fetchType 表示延迟加载还是立即加载 ‍ 修改测试方法:

@Test
public void testFindAll(){
    List<Account> accounts = iAccountDao.findAll();
    for(Account account : accounts){
        System.out.print(account);
        System.out.println(account.getUser());
    }
}
1
2
3
4
5
6
7
8

‍ 可以看到能正常查询:

# 一对多查询

我们试着在查询用户的时候,查询其所有账户,也就是一对多 ‍ 我们先在 IAcountDao 接口中新建方法:findAccountByUid

/**
 * 根据用户ID查询账户
 * @param uid
 * @return
 */
@Select("select * from account where uid = #{userId}")
List<Account> findAccountByUid(Integer uid);
1
2
3
4
5
6
7

我们在 User 类中新建 Account 属性:

// 一对多关系映射,一个用户对应多个账户
private List<Account> accounts;

public List<Account> getAccounts() {
    return accounts;
}

public void setAccounts(List<Account> accounts) {
    this.accounts = accounts;
}
1
2
3
4
5
6
7
8
9
10

‍ 然后在 IUserDao 中增加一对多查询配置:这里我们选择懒加载,关键是第 9 行









 



@Select("select * from user")
@Results(id = "userMap", value = {
        @Result(id=true, column = "id", property = "userId"),
        @Result(column = "username", property = "userName"),
        @Result(column = "address", property = "userAddress"),
        @Result(column = "sex", property = "userSex"),
        @Result(column = "birthday", property = "userBirthday"),
        @Result(column = "id", property = "accounts", 
                many = @Many(select = "com.peterjxl.dao.IAccountDao.findAccountByUid", fetchType = FetchType.LAZY))
})
List<User> findAll();
1
2
3
4
5
6
7
8
9
10
11

‍ 修改测试方法:

@Test
public void testFindAll(){
    List<User> users = userDao.findAll();
    for(User user : users){
        System.out.print(user);
        System.out.println(user.getAccounts());
    }
}
1
2
3
4
5
6
7
8

可以看到,能正常查询,并且是延迟加载的模式

‍

# 缓存的配置

‍ 我们修改测试方法,看看有无一级缓存:

@Test
public void testFindOne(){
    User user = userDao.findById(41);
    System.out.println(user);

    User user2 = userDao.findById(41);
    System.out.println(user2);
  
    System.out.println( "user == user2 ? " + (user == user2));
}
1
2
3
4
5
6
7
8
9
10

‍ 运行结果:可以看到,一级缓存是存在的。

user == user2 ? true
1

‍ 我们新建一个测试类

public class SecondLevelCatchTest {
    private InputStream in;
    private SqlSessionFactory factory;

    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    @After
    public void destroy() throws IOException {
        in.close();
    }

    @Test
    public void testFindOne(){
        SqlSession session = factory.openSession();
        IUserDao userDao = session.getMapper(IUserDao.class);
        User user = userDao.findById(41);
        System.out.println(user);
        session.close();    //释放一级缓存
    
        SqlSession session1 = factory.openSession();    //再次打开session
        IUserDao userDao1 = session1.getMapper(IUserDao.class);
        User user1 = userDao1.findById(41);
        System.out.println(user1);
        session1.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

‍ 可以看到 testFindOne 会查询两次查询,因为我们没有配置二级缓存:

我们在 IUserDao 接口上,加一个注解即可开启二级缓存:blocking 默认是 false,我们改成 true

@CacheNamespace(blocking = true)
public interface IUserDao {
1
2

‍ 可以看到值查询了一次

# 源码

所有代码已上传到了 GitHub (opens new window) 和 Gitee (opens new window) 上,并且创建了分支 demo20,读者可以通过切换分支来查看本文的示例代码。

上次更新: 2025/6/3 09:31:54
Mybatis 的注解开发-CRUD
全文检索的概念

← Mybatis 的注解开发-CRUD 全文检索的概念→

最近更新
01
新闻合订本 2025-10
10-31
02
2025 年 10 月记
10-30
03
用 AI 批量优化思源笔记排版
10-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式