java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > MyBatis一对多@Many

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

作者: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 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文