感悟一下:
好记性不如烂笔头,因为最近面试,看太多java特性原理,项目大脑开始过滤了,导致问了这个问题不知道在说啥。。回顾一下
一、基本环境配置
1.依赖导入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.atguigu</groupId>
<artifactId>mybatis_plus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis_plus</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>2.1.4</version>-->
<!-- </dependency>-->
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.配置信息
#数据库的相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis1x?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
# MyBatis Mapper所对应的XML文件位置
mybatis-plus.mapper-locations= classpath*:/static/*Mapper.xml
mybatis-plus.type-aliases-package= com.atguigu.mybatis_plus.entity
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.configuration.map-underscore-to-camel-case=true
#全局设置主键生成策略
#mybatis-plus.global-config.db-config.id-type=auto
3.数据库创建
/*
Navicat Premium Data Transfer
Source Server : localhost_3306
Source Server Type : MySQL
Source Server Version : 80017
Source Host : localhost:3306
Source Schema : mybatis1x
Target Server Type : MySQL
Target Server Version : 80017
File Encoding : 65001
Date: 24/11/2021 17:01:36
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`a_id` int(11) NOT NULL AUTO_INCREMENT,
`money` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`u_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`a_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES (1, '100', 1);
INSERT INTO `account` VALUES (2, '200', 2);
INSERT INTO `account` VALUES (3, '300', 3);
INSERT INTO `account` VALUES (4, '400', 4);
INSERT INTO `account` VALUES (5, '110', 1);
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`role_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '总裁', '管理公司');
INSERT INTO `role` VALUES (2, '经理', '管理部门');
INSERT INTO `role` VALUES (3, '组长', '管理小组');
INSERT INTO `role` VALUES (4, '县长', '管理县');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '牛一', '海南', '男');
INSERT INTO `user` VALUES (2, '牛二', '海南', '女');
INSERT INTO `user` VALUES (3, '京一', '北京', '男');
INSERT INTO `user` VALUES (4, '京二', '北京', '女');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`role_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 4);
INSERT INTO `user_role` VALUES (3, 2, 2);
INSERT INTO `user_role` VALUES (4, 3, 3);
INSERT INTO `user_role` VALUES (5, 4, 4);
SET FOREIGN_KEY_CHECKS = 1;
二、一对一
1.Account实体类
package com.atguigu.mybatis_plus.entity;
import lombok.Data;
@Data
public class Account {
private Integer aId;
private Integer uId;
private Double money;
//一个账号只有一个用户。1-1
private User user;//对应association property="user" user指的就是这个对象
@Override
public String toString() {
return "Account{" +
"aId=" + aId +
", uId=" + uId +
", money=" + money +
'}';
}
}
2.User实体类
package com.atguigu.mybatis_plus.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private String address;
private String sex;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
3.AccountMapper接口
package com.atguigu.mybatis_plus.mapper;
import com.atguigu.mybatis_plus.entity.Account;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface AccountMapper {
//查找所有账号,每个账号对应一个用户
List<Account> findAll();
}
4.AccountMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis_plus.mapper.AccountMapper">
<!--定义封装account和user的resultmap-->
<resultMap id="accountUserMap" type="account">
<id property="aId" column="aid"/>
<result property="uId" column="uid"/>
<result property="money" column="money"/>
<!-- 一对一的关系映射:配置封装user的内容-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"/>
<result column="name" property="name"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountUserMap">
select u.*,a.a_id as aid,a.u_id as uid,a.money from account a , user u where u.id = a.u_id
</select>
</mapper>
5.测试类
package com.atguigu.mybatis_plus;
import com.atguigu.mybatis_plus.entity.Account;
import com.atguigu.mybatis_plus.entity.User1;
import com.atguigu.mybatis_plus.mapper.AccountMapper;
import com.atguigu.mybatis_plus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private AccountMapper accountMapper;
@Test
public void findAll() {
List<Account> list= accountMapper.findAll();
// System.out.println(list);
for (Account a:list) {
a.toString();
System.out.println(a.getUser());
}
}
}
结果
三、一对多
1.在User类中添上
//一个用户对应多个账户,也就是一个User有多个Account对象。
private List<Account> account;
2.UserMapper接口
package com.atguigu.mybatis_plus.mapper;
import com.atguigu.mybatis_plus.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface UserMapper {
//查询所有操作,同时获取到用户下所有账户的信息
List<User> findAll();
//根据用户id找某个用户信息
User findById(int id);
}
3.UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis_plus.mapper.UserMapper">
<!--定义封装account和user的resultmap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="account" ofType="account">
<id property="aId" column="a_id"/>
<result property="money" column="money"/>
<result property="uId" column="u_id"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userAccountMap">
select id,name,address,sex,a.* from user left outer join account a on user.id = a.u_id
</select>
<select id="findById" resultMap="userAccountMap" parameterType="integer">
select id,name,address,sex,a.* from user left outer join account a on user.id = a.u_id WHERE id = #{id}
</select>
</mapper>
4.测试类加上方法
@Test
public void userfind() {
List<User> list= userMapper.findAll();
for (User a:list) {
a.toString();
System.out.println(a.getAccount());
}
User user = userMapper.findById(1);
System.out.println(user);
System.out.println(user.getAccount());
}
结果
四、多对多
1.Role实体类
package com.atguigu.mybatis_plus.entity;
import lombok.Data;
import java.util.List;
@Data
public class Role {
private Integer roleId;
private String roleName; //名称
private String roleDesc; //管啥的
//一个角色可以分配给多个用户
private List<User> users; //
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
2.在User类中添上
//一个用户有多个角色
private List<Role> roles;
3.RoleMapper接口
package com.atguigu.mybatis_plus.mapper;
import com.atguigu.mybatis_plus.entity.Role;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface RoleMapper {
List<Role> findRoles();
}
4.RoleMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis_plus.mapper.RoleMapper">
<resultMap id="roleUserMap" type="role">
<id property="roleId" column="role_id"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
<collection property="users" ofType="user">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</collection>
</resultMap>
<select id="findRoles" resultMap="roleUserMap">
select role.*,user.* from user,role, user_role WHERE role.role_id=user_role.role_id and user.id=user_role.user_id
</select>
</mapper>
5.UserMapper添加
//查找用户和他的角色
List<User> findRole();
6.UserMapper.xml中添加
<!--定义封装Role和user的resultmap-->
<resultMap id="userRole" type="user">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="roles" ofType="role">
<id property="roleId" column="role_id"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
</collection>
</resultMap>
<select id="findRole" resultMap="userRole">
select user.*,role.* from user,role, user_role WHERE role.role_id=user_role.role_id and user.id=user_role.user_id
</select>
7.测试类加上方法
@Test
public void roleUserfind() {
List<Role> list= roleMapper.findRoles();
for (Role a:list) {
a.toString();
System.out.println(a.getUsers());
}
}
@Test
public void userRolefind() {
List<User> list= userMapper.findRole();
for (User a:list) {
a.toString();
System.out.println(a.getRoles());
}
}
结果:
UserMapper中查找
用户和他对应的权限
n:n
RoleMapper中查找
权限对应的用户
n:n
五、总结
1.association
在我们实体关系对应1-1的时候,可以采用
association对应的实体只有一个对象
可以理解为association是为了打开这层User对象,进去映射sql查到User相关的结果。
2.collection
在我们实体关系对应1-n的时候,可以采用
反过来n-1也一样的道理。
collection对应的实体可以有很多对象,是个List容器
!!!
如果上层id和collection中的id对应有多个一样的,只会存找到的第一个。
比如查找到的数据
<== Row: 1, 总裁, 管理公司, 1, 牛一, 海南, 男
<== Row: 1, 县长, 管理县, 1, 牛一, 海南, 男
<== Row: 2, 经理, 管理部门, 2, 牛二, 海南, 女
<== Row: 3, 组长, 管理小组, 3, 京一, 北京, 男
关键字有两组11,只会存第一个。
可以理解为collection拿了个袋子,给每个顾客挑选关键部位不一样的数据放进去。
希望能给迷惑的你带来一些帮助~
六、拓展问题
在我们
1对多查询的
过程中,如果需要分页,就会出现
分页效果不理想
。
怎么个不理想呢?
先普及一下:
limit 0,2
代表从下标0开始,往后找2条数据
limit 2
代表从头开始找,往后找2条数据
举个User的例子:比如我们分页应该是,一页里面有几个用户。我们根据SQL的分页规则来控制数据量。回溯到我们之前查询User以及其账号的 sql语句
select id,name,address,sex,a.* from user left outer join account a on user.id = a.u_id
尝试分页:
select id,name,address,sex,a.* from user left outer join account a on user.id = a.u_id limit 0,2 #查询两条
可以看到结果 牛一 的数据丢失了一个。
解决方案:
1️⃣从sql处解决,查询语句中改为聚合类型,用
GROUP_CONCAT()
配合
group by
去拼接 多数据字段。
select id,name,address,sex,GROUP_CONCAT(a.a_id) a_id,GROUP_CONCAT(a.money) money,GROUP_CONCAT(a.u_id) u_id from user left outer join account a on user.id = a.u_id GROUP BY id LIMIT 0,2
这样牛一和牛二的数据都有了,而且牛一的数据没有丢失。
!注意:
这样查询的话就
不属于 1:n,不能使用collection去接收
类型的查询了。需要重新定义接收的实体等。
2️⃣ 从serviceImpl层解决,因为我们可以通过1:n的查询方式,获得每个User实体的所有数据(都封装在一个User类中),所以我们在serviceImpl层去获取所有的结果后,只取其中的分页数据就行。
// limit begin,sum 比如每页2条数据,第一次 limit 0,2 第二次 limit 2,2 .....
int begin=0; //从哪开始找
int sum=2; //找几条
int index = begin; //定位
List<User> allList = userMapper.findAll();
List<User> list = new ArrayList<>();
//获取其中第一第二条的。
for (int i = 0; i <sum; i++) {
list.add(allList.get(index));
index++;
}
//展示
for (User a : list) {
a.toString();
System.out.println(a.getAccount());
}
结果: