MyBatis一对多关系使用@Many注解的实现

 更新时间:2025年11月28日 09:57:47   作者:Sugarian  
本文介绍了在MyBatis中实现一对多查询的方法,包括数据表和数据类的设计,以及使用@Many注解进行查询,具有一定的参考价值,感兴趣的可以了解一下

一对多关系

在讨论使用 MyBatis 实现一对多查找之前,有必要在数据表和数据类设计层次上明确一对多关系。
假设一个用户有多个账户。在最简单的情况下,用户表仅包含 user_id 和 user_name 列,而账户表则包含 account_id、account_name 和 user_id 外键,其中 *_id 列为各个表的主键。
现在来看数据类的设计。一个用户拥有多个账号,自然想到 User 类中包含一个 Account 列表。但是,Account 类中能包含 User 对象吗?
如果 Account 中包含 User 对象,这意味着用户的信息有泄露的可能(如果用户表还包含其他隐私信息)。比如,当我们只需要知道用户的某个账号时,却附赠了用户的一系列其他信息。另外这种互相包含的关系也容易导致写出无限递归的查询语句。Account 要为 User 赋值,而 User 中包含 Account 列表,Account 列表中的元素要为 User 赋值……
这里给出感觉合理的数据表和数据类模型。

# users table
CREATE TABLE `users` (
  `user_id` int NOT NULL,
  `user_name` varchar(45) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
// user 类,忽略 setter 和 getter 
public class User {
    private Integer userId;
    private String userName;
    private List<Account> accounts;
}
# accounts table
CREATE TABLE `accounts` (
  `account_id` int NOT NULL,
  `account_name` varchar(45) NOT NULL,
  `user_id` int NOT NULL,
  PRIMARY KEY (`account_id`),
  KEY `user_id_idx` (`user_id`),
  CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
// account 类,忽略 setter 和 getter 
public class Account {
    private Integer accountId;
    private String accountName;
    private Integer userId;
}

MyBatis 一对多查询

查询的主要难度在查询 User 上,其关键是理解 @Many 注解相关的参数。
先把简单的 AccountDao 搞了。

@Mapper
public interface AccountDao {
    @Results(id = "accountResultMap", value = {
            @Result(property = "accountId", column = "account_id", id = true),
            @Result(property = "accountName", column = "account_name"),
            @Result(property = "userId", column = "user_id")
    })
    @Select(value = "SELECT * FROM accounts WHERE account_id = #{id}")
    public Account findAccountById(@Param("id") Integer id);

    @ResultMap(value = "accountResultMap")
    @Select(value = "SELECT * FROM accounts WHERE user_id=#{id}")
    public List<Account> findAccountByUserId(@Param("id") Integer id);
}

注意:这里我们定义了一个 findAccountByUserId 查询函数。因为 User 类在填充 Account 列表时,是用 user_id 进行查询的。
再看 UserDao。

@Mapper
public interface UserDao {
    @Results(id = "userResultMap", value = {
            @Result(property = "userId", column = "user_id", id = true),
            @Result(property = "userName", column = "user_name"),
            @Result(property = "accounts", column = "user_id", javaType = List.class,
                    many = @Many(select = "com.sugarian.dao.AccountDao.findAccountByUserId"))
    })
    @Select(value = "SELECT * FROM users WHERE user_id=#{id}")
    public User findUserById(@Param("id") Integer id);
}

注意下面抽取的部分

@Result(property = "userName", column = "user_name"),
            @Result(property = "accounts", column = "user_id", javaType = List.class,
                    many = @Many(select = "com.sugarian.dao.AccountDao.findAccountByUserId"))
    })

User 中的 accounts 是存放 Account 的列表,其在表结构中是没有对应的列,所以它对应的这条 @Result 实际上是再次执行了一次 sql 索引,然后将值填充到 accounts 中。另外一点,请看 column 是 user_id,这实际上就是以 user_id 作为参数,findAccountByUserId 用进行索引。
我们可以看看调试工具给出的信息:

2022-11-25 23:39:09,552 [DEBUG] com.sugarian.dao.UserDao.findUserById - ==>  Preparing: SELECT * FROM users WHERE user_id=?
2022-11-25 23:39:09,552 [DEBUG] com.sugarian.dao.UserDao.findUserById - ==> Parameters: 1(Integer)
2022-11-25 23:39:09,553 [DEBUG] com.sugarian.dao.AccountDao.findAccountByUserId - ====>  Preparing: SELECT * FROM accounts WHERE user_id=?
2022-11-25 23:39:09,553 [DEBUG] com.sugarian.dao.AccountDao.findAccountByUserId - ====> Parameters: 1(Integer)
2022-11-25 23:39:09,556 [DEBUG] com.sugarian.dao.AccountDao.findAccountByUserId - <====      Total: 3
2022-11-25 23:39:09,556 [DEBUG] com.sugarian.dao.UserDao.findUserById - <==      Total: 1

明显执行了两次 sql 查询。对于第二个查询,它从第一个查询结果中取出其中的 user_id 列,作为查询的参数。
其他参数如 javaType 指定返回类型。@Many 中的参数 select 指定第二次查询用的函数。

到此这篇关于MyBatis一对多关系使用@Many注解的实现的文章就介绍到这了,更多相关MyBatis一对多@Many 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 用html css javascript打造自己的RIA图文教程

    用html css javascript打造自己的RIA图文教程

    用html&css&javascript打造自己的RIA之一,包括了配置等
    2009-07-07
  • 解决IDEA中同项目引用报红问题

    解决IDEA中同项目引用报红问题

    在IDEA中,如果项目引用报红,可能是因为IDEA的引用缓存问题,可以通过File->Invalidate Caches/Restart清空缓存并重建索引来解决,这个方法可以帮助解决同项目中引用找不到的问题,恢复正常的项目引用,消除报红
    2024-09-09
  • Hadoop环境配置之hive环境配置详解

    Hadoop环境配置之hive环境配置详解

    这篇文章主要介绍了Hadoop环境配置之hive环境配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 支持SpEL表达式的自定义日志注解@SysLog介绍

    支持SpEL表达式的自定义日志注解@SysLog介绍

    这篇文章主要介绍了支持SpEL表达式的自定义日志注解@SysLog,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Java Stream函数式编程管道流结果处理

    Java Stream函数式编程管道流结果处理

    这篇文章主要为大家介绍了Java Stream函数式编程管道流结果处理的示例过程解析需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • 冒泡排序算法原理及JAVA实现代码

    冒泡排序算法原理及JAVA实现代码

    关键字较小的记录好比气泡逐趟上浮,关键字较大的记录好比石块下沉,每趟有一块最大的石块沉底
    2014-01-01
  • MybatisPlus 主键策略的几种实现方法

    MybatisPlus 主键策略的几种实现方法

    MybatisPlus-Plus支持多种主键生成策略,可以通过@TableId注解的type属性配置,主要策略包括AUTO、INPUT、ASSING_ID、ASSING_UUID和NONE,每种策略适用于不同的场景,下面就来介绍一下
    2024-10-10
  • java数组排序示例分享

    java数组排序示例分享

    这篇文章主要介绍了java数组排序示例,需要的朋友可以参考下
    2014-03-03
  • Java实现按键精灵的示例代码

    Java实现按键精灵的示例代码

    这篇文章主要为大家详细介绍了如何利用Java语言实现按键精灵,文中的示例代码讲解详细,对我们学习或工作有一定的参考价值,感兴趣的可以学习一下
    2022-05-05
  • java实现砸金蛋抽奖功能

    java实现砸金蛋抽奖功能

    这篇文章主要为大家详细介绍了java实现砸金蛋抽奖功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11

最新评论