1. MyBatis高级查询
1.1 resultType和resultMap属性
1.1.1 resultType
查询结果返回的类型,返回的结果字段名一定是要相同的,不一致的话会映射不成功
<select id="findByLabelName" resultType="com.jin10.vo.LabelVo">
select * from label where label_name = #{labelName}
</select>
1.1.2 resultMap
和上面的resultType相比,这个更加类似于自定义映射,可以解决复杂的映射问题,也可以解决上面字段不一致导致的映射不成功的问题
<!--id当前命名空间中的一个唯一标识,用于标识唯一一个resultMap,type表示类的完全限定名, 或者一个类型别名-->
<resultMap id="baseResultMap" type="com.jin10.vo.CategoriesVo">
<!--主键id-->
<id property="id" column="categories_id"></id>
<!--数据库中普通字段结果映射-->
<result property="groupName" column="categories_name"></result>
<result property="createTime" column="create_time"></result>
</resultMap>
1.2 多条件查询
三种方式进行多条件查询:1. 传递pojo对象(推荐);2. 使用注解@Param()获取参数;3. 使用序号进行代替
1.2.1 传递pojo对象
List<User> findByIdAndName(User user);
<select id="findByIdAndName" resultMap="baseResultMap" parameterType="com.lagou.domain.User">
select * from user where id = #{user.id} and username = #{user.name};
</select>
1.2.2 使用注解进行获取参数
List<User> findByIdAndName(@Param("id") Integer id, @Param("name") String name);
<select id="findByIdAndName" resultMap="baseResultMap">
select * from user where id = #{id} and username = #{name};
</select>
1.2.3 使用序号传递参数
List<User> findByIdAndName(Integer id, String name);
<select id="findByIdAndName" resultMap="baseResultMap">
select * from user where id = #{arg0} and username = #{arg1};
<!--或者下面这种方式-->
select * from user where id = #{param1} and username = #{param2};
</select>
总结:相对比上面三种多条件查询方式,传递pojo对象的方式会更加的直观和方便,基于注解的方式也可以,第三种方式的话就适当的了解一下,不太推荐使用这种方式
1.3 模糊查询
1.3.1 方式一,使用#{}占位符进行查询
List<User> findByUsername(String username);
<select id="findByUsername" resultMap="baseResultMap" parameterType="string">
select * from user where like #{name};
</select>
public void test() {
userMapper.findByUserName("%用户名%");
}
1.3.2 方式二,使用${}进行查询
List<User> findByUsername(String username);
<select id="findByUsername" resultMap="baseResultMap" parameterType="string">
select * from user where like '${name}';
</select>
public void test() {
userMapper.findByUserName("%用户名%");
}
总结:#{}和${}两者之间的比较
-
{} 表示的是一个占位符,在转化为sql语句的时候会自动的添加上单引号
- 实现preparedStatement向占位符中设置值,自动进行Java类型和JDBC类型转换,可以有效地防止SQL注入
- 可以接收简单类型或者pojo属性值
- 如果parameterType传递单个简单类型值,#{}括号中名称可以随便写
-
${} 表示拼接字符串
- 将parameterType传入的内容拼接在sql中且不进行JDBC类型转换,会出现sql注入的问题
- 可以接收简单类型或者pojo属性值
- 如果parameterType传递单个简单类型值,#{}括号中名称只能是value
2. 映射配置文件深入
2.1 返回主键
在应用场景中,经常会在插入数据之后进行返回当前主键id,Mybatis提供了两种返回插入数据的主键方式
2.1.1 方式一
public interface UserMapper() {
int save(User user);
}
<!--
useGeneratedKeys属性:声明返回主键
keyProperty:把返回的主键值封装到实体的id属性中
-->
<insert id="save" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into 'user' (username, birthday, sex, address) values (#{user}, #{birthday}, #{sex}, #{address})
</insert>
public void test() {
User insert = new User();
insert.setUsername("测试名字");
insert.setBirthday(new Date());
insert.setSex("man");
insert.setAddress("广东广州");
userMapper.save(insert);
}
上面的这种方法不能满足所有的数据库,对于数据库本身没有自动生成主键的Oracle来说是没有作用的
2.1.2 方式二(适用于所有的数据库)
public interface UserMapper() {
int save(User user);
}
<!--
keyColumn属性:声明返回主键
keyProperty:把返回的主键值封装到实体的id属性中
resultType: 指定主键的类型
order: 设置在SQL语句执行之前(后)执行该语句,Oracle设置order为BEFORE
-->
<insert id="save" parameterType="user">
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID();
</selectKey>
insert into 'user' (username, birthday, sex, address) values (#{user}, #{birthday}, #{sex}, #{address})
</insert>
public void test() {
User insert = new User();
insert.setUsername("测试名字");
insert.setBirthday(new Date());
insert.setSex("man");
insert.setAddress("广东广州");
userMapper.save(insert);
}
2.2 动态SQL语句
动态SQL语句是MyBatis里面的一个重大特性
2.2.1 if标签(很常用)
List<User> findByIf(User user);
<select id="findByIf" parameterType="user" resultType="User">
select * from user
<!-- Where标签相当于where 1=1,如果没有条件,就不会拼接where关键字-->
<where>
<if test="id != null">
AND id = #{id}
</if>
<if test="username != null">
AND username = #{username}
</if>
</where>
</select>
public void test() {
User select = new User();
select.setId(10);
select.setUsername("测试名字");
userMapper.findByIf(select);
}
2.2.2 set标签
更新操作使用set可以免去一些不必要的麻烦
void update();
<update id="update" parameterType="user">
UPDATE user
<!--
set标签的作用:
1. 可以代替update 表名 set ...的SQL语句中的set关键字,使用set标签会自动加上去
2. 会自动去除最后一个条件的逗号
-->
<set>
<if test="username != null">
username = #{username},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
<if test="sex != null">
sex = #{sex},
</if>
<if test="address != null">
address = #{address},
</if>
</set>
WHERE id = #{id}
</update>
public void test() {
User select = new User();
select.setId(10);
select.setUsername("测试名字");
insert.setBirthday(new Date());
insert.setSex("man");
insert.setAddress("广东肇庆");
userMapper.update(insert);
}
2.3 foreach标签
常用场景是对集合进行遍历
<foreach>标签,它的属性:
- collection:代表要遍历的集合元素
- open:代表语句的开始部分
- close:代表结束部分
- item:代表遍历集合的每个元素,生成的变量名
- sperator:代表分隔符
2.3.1 集合
List<User> findByList(List<Integer> ids);
<select id="findByList" resultType="User" parameterType="list">
select * from `user`
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
public void test() {
List<Integer> ids = new ArrayList<>();
ids.add(46);
ids.add(48);
ids.add(51);
userMapper.findByList(ids);
}
2.3.2 数组
List<User> findByArray(List<Integer> ids);
<select id="findByArray" resultType="User" parameterType="int">
select * from `user`
<where>
<foreach collection="array" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
public void test() {
Integer[] ids = {46, 48, 51};
userMapper.findByArray(ids);
}
如果是普通数组,collection属性值为array
2.4 SQL片段
主要是将多个标签出现重复的SQL语句进行抽取出来,然后在使用到的地方通过 include 引用,从而达到重复使用的效果
<!--抽取的sql片段-->
<sql id="selectUser">
SELECT * FROM `user`
</sql>
<select id="findByList" resultType="User" parameterType="list">
<include refid="selectUser">
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
3. 核心配置文件深入
3.1 plugins标签
通过plugins标签可以使用第三方的插件进行功能的扩展,例如pageHelper是将分页的复杂操作进行封装
使用步骤:
- 导入PageHelper的相关依赖
<!-- 分页助手 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
- 在MyBatis核心配置文件中配置PageHelper插件
<!-- 分页助手的插件 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 指定方言 -->
<property name="dialect" value="mysql"/>
</plugin>
- 测试
@Test
public void testPageHelper() {
//设置分页参数
PageHelper.startPage(1,2);
List<User> select = userMapper.select(null);
for(User user : select){
System.out.println(user);
}
}
4. Mybatis多表查询
数据准备
CREATE DATABASE `mybatis_db`;
USE `mybatis_db`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- insert....
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'子慕','2020-11-11 00:00:00','男','北京海淀'),(2,'应颠','2020-12-12 00:00:00','男','北京海淀');
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ordertime` VARCHAR(255) DEFAULT NULL,
`total` DOUBLE DEFAULT NULL,
`uid` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
CONSTRAINT `orders_ibfk_1`
FOREIGN KEY (`uid`)
REFERENCES `user` (`id`))
ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ------------------------------ Records of orders-- ----------------------------
INSERT INTO `orders` VALUES ('1', '2020-12-12', '3000', '1');
INSERT INTO `orders` VALUES ('2', '2020-12-12', '4000', '1');
INSERT INTO `orders` VALUES ('3', '2020-12-12', '5000', '2');
-- ------------------------------ Table structure for sys_role-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`rolename` VARCHAR(255) DEFAULT NULL,
`roleDesc` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`))
ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ------------------------------ Records of sys_role-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'CTO', 'CTO');
INSERT INTO `sys_role` VALUES ('2', 'CEO', 'CEO');
------------------------------ Table structure for sys_user_role-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`userid` INT(11) NOT NULL,
`roleid` INT(11) NOT NULL,
PRIMARY KEY (`userid`,`roleid`),
KEY `roleid` (`roleid`),
CONSTRAINT `sys_user_role_ibfk_1`
FOREIGN KEY (`userid`)
REFERENCES `sys_role`(`id`),
CONSTRAINT `sys_user_role_ibfk_2`
FOREIGN KEY (`roleid`) REFERENCES `user`(`id`))
ENGINE=INNODB DEFAULT CHARSET=utf8;
-- ------------------------------ Records of sys_user_role-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '1');
INSERT INTO `sys_user_role` VALUES ('1', '2');
INSERT INTO `sys_user_role` VALUES ('2', '2');
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
4.1 一对一查询
需求:查询指定订单号的订单和对应的用户信息
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
4.1.1 代码实现
Order实体类
package com.fuyi.entity;
import java.util.Date;
/**
* @author raofy
* @date 2021-05-11 17:34
* @desc
*/
public class Order {
private Integer id;
private Date ordertime;
private double money;
@Override
public String toString() {
return "Order{" +
"id=" + id +
", ordertime=" + ordertime +
", money=" + money +
", user=" + user +
'}';
}
}
编写Mapper接口
package com.fuyi.mapper;
import com.fuyi.entity.Order;
import java.util.List;
/**
* @author raofy
* @date 2021-05-11 17:36
* @desc
*/
public interface OrderMapper {
/**
* 查询所有订单和对应的用户信息(一对一,多对一)
* @return
*/
List<Order> findAllWithUser();
}
编写Mapper.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.fuyi.mapper.OrderMapper">
<resultMap id="baseResultMap" type="com.fuyi.entity.Order">
<id property="id" column="id"></id>
<result property="money" column="total"></result>
<result property="ordertime" column="ordertime"></result>
<!--
一对多,多对一,使用association进行相关联
property="username" Java实体类的属性名
column="username" 表中字段名
关联条件id = uid
-->
<association property="user" javaType="com.fuyi.entity.User">
<id property="id" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<select id="findAllWithUser" resultMap="baseResultMap">
SELECT * FROM orders o left join user u on o.uid = u.id
</select>
</mapper>
配置sqlMapConfig.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--环境配置-->
<environments default="development">
<!--使用MySQL环境-->
<environment id="development">
<!--使用JDBC类型事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--使用连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis_db?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
<!--加载映射配置-->
<mappers>
<!--批量加载-->
<package name="com.fuyi.mapper"/>
</mappers>
</configuration>
编写测试类
package com.fuyi.test;
import com.fuyi.entity.Order;
import com.fuyi.mapper.OrderMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author raofy
* @date 2021-05-11 17:49
* @desc
*/
public class OrderTest {
/**
* 一对一,多对一测试例子
*/
@Test
public void oneToOneTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 获取mapper
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
// 5. 执行查询
List<Order> result = mapper.findAllWithUser();
// 6. 打印结果
result.forEach(System.out::println);
sqlSession.close();
resourceAsStream.close();
}
}
总结
- 编写实体类
- 编写对应的mapper接口
- 编写对应的SQL语句和映射结果
- 测试
4.2 一对多查询
查询所有用户的对应的用户订单表
4.2.1 编写实体类
package com.fuyi.entity;
import java.util.Date;
import java.util.List;
/**
* @author raofy
*/
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Order> orderList;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", orderList=" + orderList +
'}';
}
}
4.2.2 编写mapper
List<User> findAllWithOrder();
4.2.3 编写mapper.xml文件
<resultMap id="baseResultMap" type="com.fuyi.entity.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--
一对多使用collection 标签进行关联
property="orderList" 封装到集合的属性名
ofType="com.fuyi.entity.Order" 封装集合的泛型类型
-->
<collection property="orderList" ofType="com.fuyi.entity.Order">
<id property="id" column="oid"></id>
<result property="ordertime" column="ordertime"></result>
<result property="money" column="total"></result>
</collection>
</resultMap>
<select id="findAllWithOrder" resultMap="baseResultMap">
select *, o.id oid from user u left join orders o on u.id = o.uid;
</select>
4.2.4 测试
@Test
public void getUsersTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 执行SQL参数
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查询
List<User> result = mapper.findAllWithOrder();
// 6. 打印
result.forEach(System.out::println);
// 7. 释放资源
sqlSession.close();
}
4.3 多对多查询
查询所用用户和对应的角色身份
4.3.1 编写实体类
package com.fuyi.entity;
/**
* @author raofy
* @version 1.0.0
* @createTime 2021-05-13 23:21
* @Description TODO
*/
public class SysRole {
private Integer id;
private String roleName;
private String roleDesc;
@Override
public String toString() {
return "SysRole{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
package com.fuyi.entity;
import java.util.Date;
import java.util.List;
/**
* @author raofy
*/
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<SysRole> roleList;
private List<Order> orderList;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", roleList=" + roleList +
", orderList=" + orderList +
'}';
}
}
4.3.2 编写mapper
List<User> findAllWithRole();
4.3.3 编写mapper.xml
<resultMap id="roleBaseResultMap" type="com.fuyi.entity.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="roleList" ofType="com.fuyi.entity.SysRole">
<id property="id" column="rid"></id>
<result property="roleName" column="roleName"></result>
<result property="roleDesc" column="roleDesc"></result>
</collection>
</resultMap>
<select id="findAllWithRole" resultMap="roleBaseResultMap">
select u.*, sr.id rid, sr.rolename, sr.roleDesc
from user u
left join sys_user_role sur
on u.id = sur.userid
left join sys_role sr
on sur.roleid = sr.id
</select>
4.3.4 测试
/**
* 多对多关联查询
*
* @throws IOException
*/
@Test
public void manyToManyTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 执行SQL参数
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查询
List<User> result = mapper.findAllWithRole();
// 6. 打印
result.forEach(System.out::println);
// 7. 释放资源
sqlSession.close();
}
4.4 本章总结
在单表或者多表查询种
- 多对一(一对一)配置:使用resultMap和association标签做映射配置
- 一对多配置:使用resultMap和collection
- 多对多配置:使用resultMap和collection
- 多对多和一对多很相似,难度在于SQL语句的编写
5. Mybatis嵌套查询
什么是嵌套查询,就是原本是多表查询中的联合语句拆分成各自的单表查询,再将他们嵌套起来进行查询
5.1 一对一
需求查询一个订单并查询出该订单的用户信息
5.1.1 SQL语句
# 查询出指定id的订单
select * from orders
# 通过上述查询出的uid外键去查询出用户信息
select * from user where id = uid
5.1.2 编写mapper
/**
* 一对一嵌套查询
* @return
*/
List<Order> findAllAndUser();
5.1.3 Mapper.xml映射文件
- OrderMapper.xml
<resultMap id="nestedQueryResultMap" type="com.fuyi.entity.Order">
<id property="id" column="id"></id>
<result property="money" column="total"></result>
<result property="ordertime" column="ordertime"></result>
<association property="user" javaType="com.fuyi.entity.User" select="com.fuyi.mapper.UserMapper.findById" column="uid"></association>
</resultMap>
<select id="findAllAndUser" resultMap="nestedQueryResultMap">
select * from orders
</select>
- UserMapper.xml
<select id="findById" resultType="com.fuyi.entity.User" parameterType="integer">
select * from user where id = #{id}
</select>
5.1.4 测试类
/**
* 一对一,多对一嵌套查询测试例子
*/
@Test
public void oneToOneNestedQueryTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 获取mapper
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
// 5. 执行查询
List<Order> result = mapper.findAllAndUser();
// 6. 打印结果
result.forEach(System.out::println);
sqlSession.close();
resourceAsStream.close();
}
5.1.5 总结
所谓的嵌套查询,就是使用association标签进行调用其他的sql语句,相比于多表查询,将问题拆成多个小问题去解决,从而简化了多表查询操作
5.2 一对多
需求查询所有用户及订单信息
5.2.1 SQL语句
# 查询所有用户
select * from user
# 通过用户的id查询所有订单信息
select * from order where uid = id
5.2.2 编写mapper
/**
* 一对多嵌套查询
*
* @return
*/
List<User> findAllAndOrder();
5.2.3 编写mapper.xml映射文件
- UserMapper.xml
<resultMap id="nestedQueryResultMap" type="com.fuyi.entity.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="orderList" ofType="com.fuyi.entity.Order" column="id" select="com.fuyi.mapper.OrderMapper.findByUid"></collection>
</resultMap>
<select id="findAllAndOrder" resultMap="nestedQueryResultMap">
select * from user
</select>
- OrderMapper.xml
<select id="findByUid" resultType="com.fuyi.entity.Order">
select * from orders where uid = #{id};
</select>
5.2.4 测试
/**
* 一对多嵌套查询
*
* @throws IOException
*/
@Test
public void oneToManyNestedQueryTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 执行SQL参数
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查询
List<User> result = mapper.findAllAndOrder();
// 6. 打印
result.forEach(System.out::println);
// 7. 释放资源
sqlSession.close();
}
5.3 多对多
需求:查询用户对应的角色身份
5.3.1 SQL语句
# 查询所有用户
select * from user
# 根据用户id查询用户的角色列表
select * from sys_role sr left join sys_user_role sur on sur.roleid = sr.id where sur.userid = id
5.3.2 编写实体类
package com.fuyi.entity;
/**
* @author raofy
* @version 1.0.0
* @createTime 2021-05-13 23:21
*/
public class SysRole {
private Integer id;
private String roleName;
private String roleDesc;
@Override
public String toString() {
return "SysRole{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
5.3.2 编写mapper
public interface UserMapper {
/**
* 多对多嵌套查询
*
* @return
*/
List<User> findAllAndRole();
}
5.3.3 编写mapper.xml映射文件
- UserMapper.xml
<resultMap id="nestedQueryRoleResultMap" type="com.fuyi.entity.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="roleList" ofType="com.fuyi.entity.SysRole" column="id" select="com.fuyi.mapper.SysRoleMapper.findByUid"></collection>
</resultMap>
<select id="findAllAndRole" resultMap="nestedQueryRoleResultMap">
select * from user
</select>
- SysRoleMapper.xml
<select id="findByUid" resultType="com.fuyi.entity.SysRole">
select * from sys_role sr left join sys_user_role sur on sur.roleid = sr.id where sur.userid = #{id}
</select>
5.3.4 测试
/**
* 多对多嵌套查询
*
* @throws IOException
*/
@Test
public void manyToManyNestedQueryTest() throws IOException {
// 1. 加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 获取SQLFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 3. 获取SQLSession对象
SqlSession sqlSession = factory.openSession();
// 4. 执行SQL参数
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查询
List<User> result = mapper.findAllAndRole();
// 6. 打印
result.forEach(System.out::println);
// 7. 释放资源
sqlSession.close();
}
5.3.5 总结
- 一对一配置:使用resultMap + association,通过column条件,执行select查询
- 一对多配置:使用resultMap + collection,通过column条件,执行select查询
- 多对多配置:使用resultMap + collection,通过column条件,执行select查询
- 优点:简化多表查询操作
- 缺点:执行多次sql语句,浪费数据库性