Mybatis-Plus用纯注解搞定一对多&多对多查询

业务中很常见的用户-角色就属于典型的多对多关系. 假设我们需要将用户信息(包括了用户对应的角色信息)查询出来

多对多

数据表结构

user表和role表的关系为多对多,即一个user可以分配多个role,一个role可以属于多个user。

1.user表

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`nickname` varchar(20) NOT NULL COMMENT '昵称',`birthday` date NOT NULL COMMENT '生日',`username` varchar(32) NOT NULL COMMENT '用户名',`password` varchar(30) NOT NULL COMMENT '密码',`status` varchar(2) NOT NULL DEFAULT '0' COMMENT '状态 ',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB;INSERT INTO `user` VALUES (1, 'lh', '2022-06-29', '李大', '123456', '0', '2022-06-29 09:02:07', '2022-06-29 09:02:07');
INSERT INTO `user` VALUES (2, 'ww', '2022-06-29', '陈大', '123456', '0', '2022-06-29 13:06:24', '2022-06-29 13:06:24');
INSERT INTO `user` VALUES (3, 'aa', '2022-06-29', '刘达', '123456', '0', '2022-06-29 13:06:48', '2022-06-29 13:06:48');

2.role表

CREATE TABLE `role` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',`name` varchar(20) NOT NULL COMMENT '角色名称',`remark` varchar(50) DEFAULT NULL COMMENT '角色描述',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB;INSERT INTO `role` VALUES (1, '系统管理员', '系统管理员');
INSERT INTO `role` VALUES (2, '数据管理员', '数据管理员');

3.user_role中间表

CREATE TABLE `user_role` (`user_id` int(11) NOT NULL COMMENT '用户id',`role_id` int(11) DEFAULT NULL COMMENT '角色id'
) ENGINE=InnoDB;INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (1, 2);
INSERT INTO `user_role` VALUES (2, 1);
INSERT INTO `user_role` VALUES (2, 2);
INSERT INTO `user_role` VALUES (3, 1);

实体类:

1.User类:

package wjw.test.mybatisplus.vo;import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;public class User implements Serializable {private static final long serialVersionUID = 1L;@TableId(type = IdType.AUTO)/*** 主键*/private Integer id;/*** 昵称*/private String nickname;/*** 生日*/private LocalDate birthday;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 状态*/private String status;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;public User() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public LocalDate getBirthday() {return birthday;}public void setBirthday(LocalDate birthday) {this.birthday = birthday;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public LocalDateTime getCreateTime() {return createTime;}public void setCreateTime(LocalDateTime createTime) {this.createTime = createTime;}public LocalDateTime getUpdateTime() {return updateTime;}public void setUpdateTime(LocalDateTime updateTime) {this.updateTime = updateTime;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("User [id=");builder.append(id);builder.append(", nickname=");builder.append(nickname);builder.append(", birthday=");builder.append(birthday);builder.append(", username=");builder.append(username);builder.append(", password=");builder.append(password);builder.append(", status=");builder.append(status);builder.append(", createTime=");builder.append(createTime);builder.append(", updateTime=");builder.append(updateTime);builder.append("]");return builder.toString();}}

2.Role类:

package wjw.test.mybatisplus.vo;import java.io.Serializable;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;public class Role implements Serializable {private static final long serialVersionUID = 1L;@TableId(type = IdType.AUTO)/*** 主键id*/private Integer id;/*** 角色名称*/private String name;/*** 角色描述*/private String remark;public Role() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("Role [id=");builder.append(id);builder.append(", name=");builder.append(name);builder.append(", remark=");builder.append(remark);builder.append("]");return builder.toString();}}

3.包含一对多关系的UserVo类:

package wjw.test.mybatisplus.vo;import java.time.LocalDate;
import java.util.List;public class UserVo {/*** 用户编号*/private Integer id;/*** 昵称*/private String nick_Name;/*** 用户名*/private String username;/*** 生日*/private LocalDate birthday;private List<Role> roles;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNick_Name() {return nick_Name;}public void setNick_Name(String nick_Name) {this.nick_Name = nick_Name;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public LocalDate getBirthday() {return birthday;}public void setBirthday(LocalDate birthday) {this.birthday = birthday;}public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}public UserVo() {super();}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("UserVo [id=");builder.append(id);builder.append(", nick_Name=");builder.append(nick_Name);builder.append(", username=");builder.append(username);builder.append(", birthday=");builder.append(birthday);builder.append(", roles=");builder.append(roles);builder.append("]");return builder.toString();}}

Mapper类:

1.RoleMapper:

package wjw.test.mybatisplus.mapper;import java.util.List;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import wjw.test.mybatisplus.vo.Role;@Mapper
public interface RoleMapper extends BaseMapper<Role> {/*** 根据指定的userId去user和user_role关联表查出该user所属role列表* @param userId* @return*/@Select("select * from role left join user_role on role.id=user_role.role_id where user_role.user_id=#{userId}")List<Role> getListByUserId(Integer userId);
}

2.UserMapper:

package wjw.test.mybatisplus.mapper;import java.util.List;import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import wjw.test.mybatisplus.vo.User;
import wjw.test.mybatisplus.vo.UserVo;@Mapper
public interface UserMapper extends BaseMapper<User> {//OneToMany一对多查询@Select("select * from user where ${ew.sqlSegment}")@Results({@Result(column = "id",property = "id"),                         // <1>@Result(column = "nickname",property = "nick_Name"),@Result(column = "id" /* 这里的id是要传递给下面查询里需要的参数 */,   //<2>property = "roles" /* 这里是UserVo类里的roles字段 */,many=@Many(select = "wjw.test.mybatisplus.mapper.RoleMapper.getListByUserId"))})List<UserVo> getList(@Param("ew") QueryWrapper wrapper);
}

<1>: @Result(column=“id”,property=“Id”),这个可以不写,也不会报错,但是会导致我们查询结果列表里每个UVO 实体的Id等属性没有值。

<2>: 这个@Result中

column, 主表中的列名,这个列的值要作为查询参数传给子查询。

property,代表子查询的查询结果关联的实体属性,就是UserVo中的roles字段。

select="wjw.test.mybatisplus.mapper.RoleMapper.getListByUserId"代表使用的子查询方法,就是RoleMapper类里的getListByUserId()方法。 意思就是查询主表,并将主表的id这个列和子查询关联起来,将id的值作为查询条件传入子查询中,子查询返回的结果存入到属性roles中.

测试

package wjw.test.mybatisplus;import java.util.List;import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import wjw.test.mybatisplus.mapper.RoleMapper;
import wjw.test.mybatisplus.mapper.UserMapper;
import wjw.test.mybatisplus.vo.User;
import wjw.test.mybatisplus.vo.UserVo;@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class MybatisPlusTests1 {@Autowiredprivate UserMapper userMapper;public MybatisPlusTests1() {//}@BeforeEachpublic void setup() {//}@AfterEachpublic void stop() {}@Testpublic void getUserInfo(){QueryWrapper<User> wrapper=new QueryWrapper();wrapper.in("id",1,2);List<UserVo> list = userMapper.getList(wrapper);System.out.println(list);}}

输出结果:

wjw.test.mybatisplus.MybatisPlusTests1 - [logStarted,61] - Started MybatisPlusTests1 in 2.855 seconds (JVM running for 3.885)
wjw.test.mybatisplus.mapper.UserMapper.getList - [debug,137] - ==>  Preparing: select * from user where (id IN (?,?))
wjw.test.mybatisplus.mapper.UserMapper.getList - [debug,137] - ==> Parameters: 1(Integer), 2(Integer)
wjw.test.mybatisplus.mapper.UserMapper.getList - [trace,143] - <==    Columns: id, nickname, birthday, username, password, status, create_time, update_time
wjw.test.mybatisplus.mapper.UserMapper.getList - [trace,143] - <==        Row: 1, lh, 2022-06-29, 李大, 123456, 0, 2022-06-29 09:02:07.0, 2022-06-29 09:02:07.0
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - ====>  Preparing: select * from role left join user_role on role.id=user_role.role_id where user_role.user_id=?
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - ====> Parameters: 1(Integer)
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====    Columns: id, name, remark, user_id, role_id
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====        Row: 1, 系统管理员, 系统管理员, 1, 1
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====        Row: 2, 数据管理员, 数据管理员, 1, 2
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - <====      Total: 2
wjw.test.mybatisplus.mapper.UserMapper.getList - [trace,143] - <==        Row: 2, ww, 2022-06-29, 陈大, 123456, 0, 2022-06-29 13:06:24.0, 2022-06-29 13:06:24.0
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - ====>  Preparing: select * from role left join user_role on role.id=user_role.role_id where user_role.user_id=?
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - ====> Parameters: 2(Integer)
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====    Columns: id, name, remark, user_id, role_id
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====        Row: 1, 系统管理员, 系统管理员, 2, 1
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [trace,143] - <====        Row: 2, 数据管理员, 数据管理员, 2, 2
w.t.mybatisplus.mapper.RoleMapper.getListByUserId - [debug,137] - <====      Total: 2
wjw.test.mybatisplus.mapper.UserMapper.getList - [debug,137] - <==      Total: 2
[UserVo [id=1, nick_Name=lh, username=李大, birthday=2022-06-29, roles=[Role [id=1, name=系统管理员, remark=系统管理员], Role [id=2, name=数据管理员, remark=数据管理员]]], UserVo [id=2, nick_Name=ww, username=陈大, birthday=2022-06-29, roles=[Role [id=1, name=系统管理员, remark=系统管理员], Role [id=2, name=数据管理员, remark=数据管理员]]]]

将user的id=1,id=2传入,得到结果如下:

[UserVo [id=1, nick_Name=lh, username=李大, birthday=2022-06-29, roles=[Role [id=1, name=系统管理员, remark=系统管理员], Role [id=2, name=数据管理员, remark=数据管理员]]], UserVo [id=2, nick_Name=ww, username=陈大, birthday=2022-06-29, roles=[Role [id=1, name=系统管理员, remark=系统管理员], Role [id=2, name=数据管理员, remark=数据管理员]]]]

可以看出表中id为1和2的user信息和其对应的角色信息都已经查询出来了。

如果传递多个参数呢?

如果select属性指定的方法需要多个参数,column的写法是这样的:column = "{查询参数1=主查询列名1, 查询参数2=主查询列名2}"

@Select({"select * from group where account_id=#{accountId} and delete_flag=0"})
@Results({@Result(property = "groupId", column = "group_id", id = true),@Result(property = "name", column = "user_name"), @Result(property = "accountId", column = "account_id"),@Result(property = "deleteFlag", column = "delete_Flag"),@Result(property = "parentId", column = "parent_Id"), @Result(property = "userList", many
//"groupId=group_id",相当于将主查询中的列group_id映射到查询参数groupId中
//"userName=user_name",相当于将主查询中的列user_name映射到查询参数userName中
=@Many(select="selectUsersByGroupId"), column = "{groupId=group_id ,userName=user_name}")})
List<Group> selectGroupWithUsers(@Param("accountId") String accountId);@Select({"select u.* from user u","inner join user_group ug on u.user_id = ug.user_id","where ug.group_id=#{groupId} and u.user_name=#{userName} and u.delete_flag=0"})
List<User> selectUsersByGroupId(@Param("groupId") String groupId, @Param("userName") String userName);

一对多

再实战一个不用中间表的一对多的例子

数据表结构

1.主表(bfs_nota1001)

CREATE TABLE `bfs_nota1001` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '与业务无关的自增主键',`f_notaunikey` char(32) NOT NULL COMMENT '标识一条记录的key,由业务字段的MD5成的32个字节的字符串',`f_head` char(12) NOT NULL COMMENT '报文头,长度(字节): 12',`f_msgtype` varchar(100) NOT NULL COMMENT '消息类型,',`f_drivercode` char(9) NOT NULL COMMENT '设备编号,长度(字节): 9',`f_qr_cdrivercode` varchar(9) NOT NULL COMMENT 'QR设备编号,长度(字节): 9',`f_qr_fdatetime` timestamp NOT NULL COMMENT 'QR封包时间',`f_qr_randomnum` char(5) NOT NULL COMMENT 'QR钞捆序号,长度(字节): 5',PRIMARY KEY (`id`),UNIQUE KEY `bfs_nota1001_un` (`f_notaunikey`)
);INSERT INTO `bfs_nota1001` VALUES (1,'3c496a9cac5986b5e9dc876f4f0401ff','GDAP20200527','1001','M02000930','M02000429','2020-05-27 09:28:39','20022');

2.子表(bfs_nota1001_detail)

CREATE TABLE `bfs_nota1001_detail` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '与业务无关的自增主键',`f_notaunikey` char(32) NOT NULL COMMENT '标识一条记录的key,由相关的表bfs_nota1001的字段f_notaunikey来赋值',`f_detailunikey` char(32) NOT NULL COMMENT '标识一条记录的key,由业务字段的MD5成的32个字节的字符串',`f_moneyslogan` char(2) NOT NULL COMMENT '钞口号,长度(字节): 2',`f_keynum` char(5) NOT NULL COMMENT '把号,长度(字节): 5',`f_backcode` char(5) NOT NULL COMMENT '银行缩写,长度(字节): 5',`f_detailbacksx` char(9) NOT NULL COMMENT '银行代码,长度(字节): 9',`f_drvercode` char(9) NOT NULL COMMENT '设备编号,长度(字节): 9',`f_btime` timestamp NOT NULL COMMENT '时间,长度(字节): 12',`f_coupons` char(3) NOT NULL COMMENT '券别,长度(字节): 3',`f_couponcount` int(11) NOT NULL COMMENT '张数,长度(字节): 4',`f_couponvalue` int(11) NOT NULL COMMENT '金额,长度(字节): 6',`f_revision` varchar(10) NOT NULL COMMENT '版本,长度(字节): 10',PRIMARY KEY (`id`),UNIQUE KEY `bfs_nota1001_detail_un` (`f_detailunikey`),KEY `bfs_nota1001_detail_key` (`f_notaunikey`)
);INSERT INTO `bfs_nota1001_detail` VALUES (1,'3c496a9cac5986b5e9dc876f4f0401ff','e5d73440e633b7783eb3fb957ae60e3','02','00019','51000','771600110','M02000429','2020-05-27 09:27:49','100',100,10000,'2015FIT   '),(2,'3c496a9cac5986b5e9dc876f4f0401ff','ad2a34af3038a87f263b8f9ea771e4f1','02','00016','51000','771600110','M02000429','2020-05-27 09:27:51','100',100,10000,'2015FIT   '),(3,'3c496a9cac5986b5e9dc876f4f0401ff','75a42347de99ece9d706dbb7c804ca0d','02','00018','51000','771600110','M02000429','2020-05-27 09:27:54','100',100,10000,'2015FIT   '),(4,'3c496a9cac5986b5e9dc876f4f0401ff','92e78b01edb6e03f3746c284e80ebc73','02','00014','51000','771600110','M02000429','2020-05-27 09:27:56','100',100,10000,'2015FIT   '),(5,'3c496a9cac5986b5e9dc876f4f0401ff','b95e2e493947c5f522546b6fa4d3ba3d','01','00022','51000','771600110','M02000429','2020-05-27 09:27:59','100',100,10000,'2015FIT   '),(6,'3c496a9cac5986b5e9dc876f4f0401ff','a5efae152a9da726807e5c9a743c1b6d','01','00025','51000','771600110','M02000429','2020-05-27 09:28:01','100',100,10000,'2015FIT   '),(7,'3c496a9cac5986b5e9dc876f4f0401ff','68cb897a34180f92a606aa5a73f20a0b','02','00015','51000','771600110','M02000429','2020-05-27 09:28:04','100',100,10000,'2015FIT   '),(8,'3c496a9cac5986b5e9dc876f4f0401ff','24ffd138d550e59243b1c65504c24d6a','01','00017','51000','771600110','M02000429','2020-05-27 09:28:06','100',100,10000,'2015FIT   '),(9,'3c496a9cac5986b5e9dc876f4f0401ff','ff9b18003d7f730a77deabeba6fd453d','02','00012','51000','771600110','M02000429','2020-05-27 09:28:09','100',100,10000,'2015FIT   '),(10,'3c496a9cac5986b5e9dc876f4f0401ff','c9ab32450ec9154b84b3ad98918030e2','01','00024','51000','771600110','M02000429','2020-05-27 09:28:12','100',100,10000,'2015FIT   ');

实体类:

1.主类(BfsNota1001)

package wjw.test.mybatisplus.slave.vo;import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;public class BfsNota1001 implements Serializable {private static final long serialVersionUID = 1L;@TableId(type = IdType.AUTO)/*** 与业务无关的自增主键*/private Long id;/*** 标识一条记录的key,由业务字段的md5成的32个字节的字符串*/private String fNotaunikey;/*** 报文头,长度(字节)*/private String fHead;/*** 消息类型,*/private String fMsgtype;/*** 设备编号,长度(字节)*/private String fDrivercode;/*** qr设备编号,长度(字节)*/private String fQrCdrivercode;/*** qr封包时间*/private LocalDateTime fQrFdatetime;/*** qr钞捆序号,长度(字节)*/private String fQrRandomnum;private List<BfsNota1001Detail> details;public BfsNota1001() {}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getfNotaunikey() {return fNotaunikey;}public void setfNotaunikey(String fNotaunikey) {this.fNotaunikey = fNotaunikey;}public String getfHead() {return fHead;}public void setfHead(String fHead) {this.fHead = fHead;}public String getfMsgtype() {return fMsgtype;}public void setfMsgtype(String fMsgtype) {this.fMsgtype = fMsgtype;}public String getfDrivercode() {return fDrivercode;}public void setfDrivercode(String fDrivercode) {this.fDrivercode = fDrivercode;}public String getfQrCdrivercode() {return fQrCdrivercode;}public void setfQrCdrivercode(String fQrCdrivercode) {this.fQrCdrivercode = fQrCdrivercode;}public LocalDateTime getfQrFdatetime() {return fQrFdatetime;}public void setfQrFdatetime(LocalDateTime fQrFdatetime) {this.fQrFdatetime = fQrFdatetime;}public String getfQrRandomnum() {return fQrRandomnum;}public void setfQrRandomnum(String fQrRandomnum) {this.fQrRandomnum = fQrRandomnum;}public List<BfsNota1001Detail> getDetails() {return details;}public void setDetails(List<BfsNota1001Detail> details) {this.details = details;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("BfsNota1001 [id=");builder.append(id);builder.append(", fNotaunikey=");builder.append(fNotaunikey);builder.append(", fHead=");builder.append(fHead);builder.append(", fMsgtype=");builder.append(fMsgtype);builder.append(", fDrivercode=");builder.append(fDrivercode);builder.append(", fQrCdrivercode=");builder.append(fQrCdrivercode);builder.append(", fQrFdatetime=");builder.append(fQrFdatetime);builder.append(", fQrRandomnum=");builder.append(fQrRandomnum);builder.append(", details=");builder.append(details);builder.append("]");return builder.toString();}}

2.子类(BfsNota1001Detail):

package wjw.test.mybatisplus.slave.vo;import java.io.Serializable;
import java.time.LocalDateTime;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;public class BfsNota1001Detail implements Serializable {private static final long serialVersionUID = 1L;@TableId(type = IdType.AUTO)/*** 与业务无关的自增主键*/private Long id;/*** 标识一条记录的key,由相关的表bfs_nota1001的字段f_notaunikey来赋值*/private String fNotaunikey;/*** 标识一条记录的key,由业务字段的md5成的32个字节的字符串*/private String fDetailunikey;/*** 钞口号,长度(字节)*/private String fMoneyslogan;/*** 把号,长度(字节)*/private String fKeynum;/*** 银行缩写,长度(字节)*/private String fBackcode;/*** 银行代码,长度(字节)*/private String fDetailbacksx;/*** 设备编号,长度(字节)*/private String fDrvercode;/*** 时间,长度(字节)*/private LocalDateTime fBtime;/*** 券别,长度(字节)*/private String fCoupons;/*** 张数,长度(字节)*/private Integer fCouponcount;/*** 金额,长度(字节)*/private Integer fCouponvalue;/*** 版本,长度(字节)*/private String fRevision;public BfsNota1001Detail() {}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getfNotaunikey() {return fNotaunikey;}public void setfNotaunikey(String fNotaunikey) {this.fNotaunikey = fNotaunikey;}public String getfDetailunikey() {return fDetailunikey;}public void setfDetailunikey(String fDetailunikey) {this.fDetailunikey = fDetailunikey;}public String getfMoneyslogan() {return fMoneyslogan;}public void setfMoneyslogan(String fMoneyslogan) {this.fMoneyslogan = fMoneyslogan;}public String getfKeynum() {return fKeynum;}public void setfKeynum(String fKeynum) {this.fKeynum = fKeynum;}public String getfBackcode() {return fBackcode;}public void setfBackcode(String fBackcode) {this.fBackcode = fBackcode;}public String getfDetailbacksx() {return fDetailbacksx;}public void setfDetailbacksx(String fDetailbacksx) {this.fDetailbacksx = fDetailbacksx;}public String getfDrvercode() {return fDrvercode;}public void setfDrvercode(String fDrvercode) {this.fDrvercode = fDrvercode;}public LocalDateTime getfBtime() {return fBtime;}public void setfBtime(LocalDateTime fBtime) {this.fBtime = fBtime;}public String getfCoupons() {return fCoupons;}public void setfCoupons(String fCoupons) {this.fCoupons = fCoupons;}public Integer getfCouponcount() {return fCouponcount;}public void setfCouponcount(Integer fCouponcount) {this.fCouponcount = fCouponcount;}public Integer getfCouponvalue() {return fCouponvalue;}public void setfCouponvalue(Integer fCouponvalue) {this.fCouponvalue = fCouponvalue;}public String getfRevision() {return fRevision;}public void setfRevision(String fRevision) {this.fRevision = fRevision;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("BfsNota1001Detail [id=");builder.append(id);builder.append(", fNotaunikey=");builder.append(fNotaunikey);builder.append(", fDetailunikey=");builder.append(fDetailunikey);builder.append(", fMoneyslogan=");builder.append(fMoneyslogan);builder.append(", fKeynum=");builder.append(fKeynum);builder.append(", fBackcode=");builder.append(fBackcode);builder.append(", fDetailbacksx=");builder.append(fDetailbacksx);builder.append(", fDrvercode=");builder.append(fDrvercode);builder.append(", fBtime=");builder.append(fBtime);builder.append(", fCoupons=");builder.append(fCoupons);builder.append(", fCouponcount=");builder.append(fCouponcount);builder.append(", fCouponvalue=");builder.append(fCouponvalue);builder.append(", fRevision=");builder.append(fRevision);builder.append("]");return builder.toString();}}

Mapper类:

BfsNota1001DetailMapper:

package wjw.test.mybatisplus.slave.mapper;import java.util.List;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import wjw.test.mybatisplus.slave.vo.BfsNota1001Detail;@Mapper
public interface BfsNota1001DetailMapper extends BaseMapper<BfsNota1001Detail> {@Select("select * from bfs_nota1001_detail where f_notaunikey=#{fNotaunikey}")@Results({@Result(id=true,column="id",property="id"),@Result(column = "f_notaunikey",property = "fNotaunikey"),@Result(column = "f_detailunikey",property = "fDetailunikey"),@Result(column = "f_moneyslogan",property = "fMoneyslogan"),@Result(column = "f_keynum",property = "fKeynum"),@Result(column = "f_backcode",property = "fBackcode"),@Result(column = "f_detailbacksx",property = "fDetailbacksx"),@Result(column = "f_drvercode",property = "fDrvercode"),@Result(column = "f_btime",property = "fBtime"),@Result(column = "f_coupons",property = "fCoupons"),@Result(column = "f_couponcount",property = "fCouponcount"),@Result(column = "f_couponvalue",property = "fCouponvalue"),@Result(column = "f_revision",property = "fRevision")})List<BfsNota1001Detail> getListByNotaunikey(@Param("fNotaunikey")String fNotaunikey);
}

BfsNota1001Mapper:

package wjw.test.mybatisplus.slave.mapper;import java.util.List;import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import wjw.test.mybatisplus.slave.vo.BfsNota1001;
import wjw.test.mybatisplus.slave.vo.BfsNota1001Detail;@Mapper
public interface BfsNota1001Mapper extends BaseMapper<BfsNota1001> {//OneToMany一对多查询@Select("select * from bfs_nota1001 where id=#{id}")@Results({@Result(column = "id",property = "id",id=true),@Result(column = "f_notaunikey",property = "fNotaunikey"),@Result(column = "f_head",property = "fHead"),@Result(column = "f_msgtype",property = "fMsgtype"),@Result(column = "f_drivercode",property = "fDrivercode"),@Result(column = "f_qr_cdrivercode",property = "fQrCdrivercode"),@Result(column = "f_qr_fdatetime",property = "fQrFdatetime"),@Result(column = "f_qr_randomnum",property = "fQrRandomnum"),@Result(column = "f_notaunikey" /* 主查询里的列名,这里的f_notaunikey是要传递给下面查询里需要的参数 */,property = "details" /* 这里是BfsNota1001Vo类里的details字段 */,many=@Many(select = "wjw.test.mybatisplus.slave.mapper.BfsNota1001DetailMapper.getListByNotaunikey"))})List<BfsNota1001> getList(@Param("id")Integer id);
}

测试

package wjw.test.mybatisplus;import java.util.List;import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;import wjw.test.mybatisplus.slave.mapper.BfsNota1001DetailMapper;
import wjw.test.mybatisplus.slave.mapper.BfsNota1001Mapper;
import wjw.test.mybatisplus.slave.vo.BfsNota1001;@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class MybatisPlusTestSlave {@Autowiredprivate BfsNota1001Mapper b1001Mapper;public MybatisPlusTestSlave() {//}@BeforeEachpublic void setup() {//}@AfterEachpublic void stop() {}@Testpublic void get1001() {List<BfsNota1001> list = b1001Mapper.getList(1);System.out.println(list);}}

输出结果:

w.t.m.slave.mapper.BfsNota1001Mapper.getList - [debug,137] - ==>  Preparing: select * from bfs_nota1001 where id=?
w.t.m.slave.mapper.BfsNota1001Mapper.getList - [debug,137] - ==> Parameters: 1(Integer)
w.t.m.slave.mapper.BfsNota1001Mapper.getList - [trace,143] - <==    Columns: id, f_notaunikey, f_head, f_msgtype, f_drivercode, f_qr_cdrivercode, f_qr_fdatetime, f_qr_randomnum
w.t.m.slave.mapper.BfsNota1001Mapper.getList - [trace,143] - <==        Row: 1, 3c496a9cac5986b5e9dc876f4f0401ff, GDAP20200527, 1001, M02000930, M02000429, 2020-05-27 17:28:39.0, 20022
w.t.m.s.m.B.getListByNotaunikey - [debug,137] - ====>  Preparing: select * from bfs_nota1001_detail where f_notaunikey=?
w.t.m.s.m.B.getListByNotaunikey - [debug,137] - ====> Parameters: 3c496a9cac5986b5e9dc876f4f0401ff(String)
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====    Columns: id, f_notaunikey, f_detailunikey, f_moneyslogan, f_keynum, f_backcode, f_detailbacksx, f_drvercode, f_btime, f_coupons, f_couponcount, f_couponvalue, f_revision
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 1, 3c496a9cac5986b5e9dc876f4f0401ff, e5d73440e633b7783eb3fb957ae60e3, 02, 00019, 51000, 771600110, M02000429, 2020-05-27 17:27:49.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 2, 3c496a9cac5986b5e9dc876f4f0401ff, ad2a34af3038a87f263b8f9ea771e4f1, 02, 00016, 51000, 771600110, M02000429, 2020-05-27 17:27:51.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 3, 3c496a9cac5986b5e9dc876f4f0401ff, 75a42347de99ece9d706dbb7c804ca0d, 02, 00018, 51000, 771600110, M02000429, 2020-05-27 17:27:54.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 4, 3c496a9cac5986b5e9dc876f4f0401ff, 92e78b01edb6e03f3746c284e80ebc73, 02, 00014, 51000, 771600110, M02000429, 2020-05-27 17:27:56.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 5, 3c496a9cac5986b5e9dc876f4f0401ff, b95e2e493947c5f522546b6fa4d3ba3d, 01, 00022, 51000, 771600110, M02000429, 2020-05-27 17:27:59.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 6, 3c496a9cac5986b5e9dc876f4f0401ff, a5efae152a9da726807e5c9a743c1b6d, 01, 00025, 51000, 771600110, M02000429, 2020-05-27 17:28:01.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 7, 3c496a9cac5986b5e9dc876f4f0401ff, 68cb897a34180f92a606aa5a73f20a0b, 02, 00015, 51000, 771600110, M02000429, 2020-05-27 17:28:04.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 8, 3c496a9cac5986b5e9dc876f4f0401ff, 24ffd138d550e59243b1c65504c24d6a, 01, 00017, 51000, 771600110, M02000429, 2020-05-27 17:28:06.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 9, 3c496a9cac5986b5e9dc876f4f0401ff, ff9b18003d7f730a77deabeba6fd453d, 02, 00012, 51000, 771600110, M02000429, 2020-05-27 17:28:09.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [trace,143] - <====        Row: 10, 3c496a9cac5986b5e9dc876f4f0401ff, c9ab32450ec9154b84b3ad98918030e2, 01, 00024, 51000, 771600110, M02000429, 2020-05-27 17:28:12.0, 100, 100, 10000, 2015FIT
w.t.m.s.m.B.getListByNotaunikey - [debug,137] - <====      Total: 10
w.t.m.slave.mapper.BfsNota1001Mapper.getList - [debug,137] - <==      Total: 1
[BfsNota1001 [id=1, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fHead=GDAP20200527, fMsgtype=1001, fDrivercode=M02000930, fQrCdrivercode=M02000429, fQrFdatetime=2020-05-27T17:28:39, fQrRandomnum=20022, details=[BfsNota1001Detail [id=1, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=e5d73440e633b7783eb3fb957ae60e3, fMoneyslogan=02, fKeynum=00019, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:27:49, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=2, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=ad2a34af3038a87f263b8f9ea771e4f1, fMoneyslogan=02, fKeynum=00016, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:27:51, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=3, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=75a42347de99ece9d706dbb7c804ca0d, fMoneyslogan=02, fKeynum=00018, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:27:54, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=4, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=92e78b01edb6e03f3746c284e80ebc73, fMoneyslogan=02, fKeynum=00014, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:27:56, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=5, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=b95e2e493947c5f522546b6fa4d3ba3d, fMoneyslogan=01, fKeynum=00022, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:27:59, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=6, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=a5efae152a9da726807e5c9a743c1b6d, fMoneyslogan=01, fKeynum=00025, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:28:01, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=7, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=68cb897a34180f92a606aa5a73f20a0b, fMoneyslogan=02, fKeynum=00015, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:28:04, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=8, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=24ffd138d550e59243b1c65504c24d6a, fMoneyslogan=01, fKeynum=00017, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:28:06, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=9, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=ff9b18003d7f730a77deabeba6fd453d, fMoneyslogan=02, fKeynum=00012, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:28:09, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ], BfsNota1001Detail [id=10, fNotaunikey=3c496a9cac5986b5e9dc876f4f0401ff, fDetailunikey=c9ab32450ec9154b84b3ad98918030e2, fMoneyslogan=01, fKeynum=00024, fBackcode=51000, fDetailbacksx=771600110, fDrvercode=M02000429, fBtime=2020-05-27T17:28:12, fCoupons=100, fCouponcount=100, fCouponvalue=10000, fRevision=2015FIT   ]]]]

后记:

MyBatis中常用的一对多查询是 N+1 方式的查询,即先查询主表再查询子表.这就是著名的 [n+1 问题] 。如果记录很多,这种查询效率是非常低效的。

有没有只需要一条SQL查询就能搞定一对多关系的呢? 请看下面的进阶文章Mybatis巧用@Many注解让一条SQL联合查询语句完成一对多查询 !

Mybatis-Plus用纯注解完成一对多多对多查询相关推荐

  1. Mybatis中的关系映射(一对一,一对多,多对多)

    在网上寻了很久,大多数讲关系性的文章都是大篇幅的去将表照搬上来,本来就很生硬,此文就不在讲述关系性映射的具体实现,转而从浅层来讲讲其概念性. 1.1 关联关系概述 在关系型数据库中,多表之间存在着三种 ...

  2. Mybatis中如何实现一对一,一对多的关联查询?

    MyBatis实现一对一.一对多关联查询一般有两种方式: 方式一:sqlMapper配置文件 一对一:在resultMap标签中使用 association 标签 一对多:在resultMap 标签中 ...

  3. mybatis plug 只查id_Mybatis一对多/多对多查询时只查出了一条数据

    问题描述: 如果三表(包括了关系表)级联查询,主表和明细表的主键都是id的话,明细表的多条数据只能查询出来第一条/最后一条数据. 三个表,权限表(Permission),权限组表(Permission ...

  4. gorm一对一 一对多 多对多查询案例

    Student -- IDCard -- Class -- Teacher

  5. Mybatis全网最详细教程(纯注解编程),包看包会!

    Mybatis的注解开发 说明:因为是纯注解,所以没有任何xml配置文件,只需要写一个before()方法,将配置代码放入即可,这里面的配置相当于sqlMapConfig.xml配置文件,后面直接调用 ...

  6. 整合mybatis——使用纯注解整合、使用Mapper+Mapper.xml整合、使用mybatis.cfg.xml整合

    引入druid <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-b ...

  7. Mybatis注解实现一对多关联映射(@Many)

    mybatis注解实现一对多关联映射 @Select("<script> \n" +"\t\tselect a.*,p.punishment_money, p ...

  8. spingboot和mybatis,纯注解方式

    文章目录 spingboot和mybatis整合 纯注解方式,不使用xml 1. 创建数据库 2. 建立工程,spring initizer: web + jbdc + mysql + mybatis ...

  9. SSM纯注解后台代码整合(Spring+SpringMvc+Mybatis)

    SSM后台整合(Spring+SpringMvc+Mybtis+事务+Rest风格+统一结果封装+统一异常处理+拦截器) 文章目录 1 基础环境搭建 1.1 建表 1.2 创建web项目 1.3 导入 ...

最新文章

  1. matlab节约里程法_芳烃产业链里程碑:唐山旭阳30万吨/年苯乙烯项目一次性开车成功...
  2. Part8 多态性 8.1运算符重载
  3. 计算机xp的解释,2017职称计算机考点:Windowsxp系统注册表的技巧
  4. DevExpress GridControl 导出为Excel
  5. centos安装DHCP服务器
  6. 编程基本功:典型的柳氏风格命名一例
  7. 使用 Sublime开发 Jade
  8. 监控视频平台LiveNVR如何给摄像头视频添加文字水印和图片水印
  9. 兰州大学第一届『飞马杯』程序设计竞赛
  10. C++图片格式转换:BMP转JPEG
  11. WPA3也不安全啦?H2E了解一下
  12. Windows系统CMD命令测试
  13. 辣椒的python之旅
  14. Caused by: java.lang.ClassNotFoundException: Cannot find class: com.lisisi.myframework.entity.Insert
  15. 大学android移动开发笔记,基于Android的移动模拟练习系统的设计与实现
  16. 艺术遇上AI,yuma kishi的工科浪漫 | 设计黑客
  17. (附源码)python方块新闻 毕业设计 091600
  18. torch之线性拟合
  19. 微信小程序蓝牙BLE开发实战——案例(二)
  20. datagrip 快捷键

热门文章

  1. sas数据操作update、modify by ke=、控制modify的更新、datasets添加约束条件、操作文件变动aduit trail...
  2. 经典功率谱估计(直接法、间接法、直接法的改进(包括Bartlett法、Welch法))
  3. python PIL库安装
  4. matlab控制流上机报告,MATLAB实验指导书(2013)要点
  5. weblogic启动报错:BEA-149265
  6. reverse()的使用
  7. golang详细知识体系
  8. 易语言传文本到c 崩溃,win7系统易语言打开支持库配置就崩溃的解决方法
  9. getopts函数简介
  10. uefi启动 多硬盘gtp_关于UEFI启动+GPT分区的一些经验