1. MyBatis高級查詢
1.1 resultType和resultMap屬性
1.1.1 resultType
查詢結(jié)果返回的類型猾愿,返回的結(jié)果字段名一定是要相同的抡驼,不一致的話會映射不成功
<select id="findByLabelName" resultType="com.jin10.vo.LabelVo">
select * from label where label_name = #{labelName}
</select>
1.1.2 resultMap
和上面的resultType相比歌殃,這個更加類似于自定義映射,可以解決復(fù)雜的映射問題外莲,也可以解決上面字段不一致導(dǎo)致的映射不成功的問題
<!--id當(dāng)前命名空間中的一個唯一標識,用于標識唯一一個resultMap,type表示類的完全限定名, 或者一個類型別名-->
<resultMap id="baseResultMap" type="com.jin10.vo.CategoriesVo">
<!--主鍵id-->
<id property="id" column="categories_id"></id>
<!--數(shù)據(jù)庫中普通字段結(jié)果映射-->
<result property="groupName" column="categories_name"></result>
<result property="createTime" column="create_time"></result>
</resultMap>
1.2 多條件查詢
三種方式進行多條件查詢:1. 傳遞pojo對象(推薦)裂垦;2. 使用注解@Param()獲取參數(shù)团赏;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 使用注解進行獲取參數(shù)
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 使用序號傳遞參數(shù)
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>
總結(jié):相對比上面三種多條件查詢方式,傳遞pojo對象的方式會更加的直觀和方便,基于注解的方式也可以,第三種方式的話就適當(dāng)?shù)牧私庖幌拢惶扑]使用這種方式
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("%用戶名%");
}
總結(jié):#{}和${}兩者之間的比較
-
{} 表示的是一個占位符雾家,在轉(zhuǎn)化為sql語句的時候會自動的添加上單引號
- 實現(xiàn)preparedStatement向占位符中設(shè)置值铃彰,自動進行Java類型和JDBC類型轉(zhuǎn)換,可以有效地防止SQL注入
- 可以接收簡單類型或者pojo屬性值
- 如果parameterType傳遞單個簡單類型值芯咧,#{}括號中名稱可以隨便寫
-
${} 表示拼接字符串
- 將parameterType傳入的內(nèi)容拼接在sql中且不進行JDBC類型轉(zhuǎn)換牙捉,會出現(xiàn)sql注入的問題
- 可以接收簡單類型或者pojo屬性值
- 如果parameterType傳遞單個簡單類型值竹揍,#{}括號中名稱只能是value
2. 映射配置文件深入
2.1 返回主鍵
在應(yīng)用場景中,經(jīng)常會在插入數(shù)據(jù)之后進行返回當(dāng)前主鍵id邪铲,Mybatis提供了兩種返回插入數(shù)據(jù)的主鍵方式
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);
}
上面的這種方法不能滿足所有的數(shù)據(jù)庫芬位,對于數(shù)據(jù)庫本身沒有自動生成主鍵的Oracle來說是沒有作用的
2.1.2 方式二(適用于所有的數(shù)據(jù)庫)
public interface UserMapper() {
int save(User user);
}
<!--
keyColumn屬性:聲明返回主鍵
keyProperty:把返回的主鍵值封裝到實體的id屬性中
resultType: 指定主鍵的類型
order: 設(shè)置在SQL語句執(zhí)行之前(后)執(zhí)行該語句,Oracle設(shè)置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 動態(tài)SQL語句
動態(tài)SQL語句是MyBatis里面的一個重大特性
2.2.1 if標簽(很常用)
List<User> findByIf(User user);
<select id="findByIf" parameterType="user" resultType="User">
select * from user
<!-- Where標簽相當(dāng)于where 1=1带到,如果沒有條件昧碉,就不會拼接where關(guān)鍵字-->
<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關(guān)鍵字,使用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:代表結(jié)束部分
- 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 數(shù)組
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);
}
如果是普通數(shù)組,collection屬性值為array
2.4 SQL片段
主要是將多個標簽出現(xiàn)重復(fù)的SQL語句進行抽取出來搪搏,然后在使用到的地方通過 include 引用狭握,從而達到重復(fù)使用的效果
<!--抽取的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是將分頁的復(fù)雜操作進行封裝
使用步驟:
- 導(dǎo)入PageHelper的相關(guān)依賴
<!-- 分頁助手 -->
<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() {
//設(shè)置分頁參數(shù)
PageHelper.startPage(1,2);
List<User> select = userMapper.select(null);
for(User user : select){
System.out.println(user);
}
}
4. Mybatis多表查詢
數(shù)據(jù)準備
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,'應(yīng)顛','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 一對一查詢
需求:查詢指定訂單號的訂單和對應(yīng)的用戶信息
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
4.1.1 代碼實現(xiàn)
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 {
/**
* 查詢所有訂單和對應(yīng)的用戶信息(一對一疯溺,多對一)
* @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進行相關(guān)聯(lián)
property="username" Java實體類的屬性名
column="username" 表中字段名
關(guān)聯(lián)條件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>
<!--環(huán)境配置-->
<environments default="development">
<!--使用MySQL環(huán)境-->
<environment id="development">
<!--使用JDBC類型事務(wù)管理器-->
<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. 執(zhí)行查詢
List<Order> result = mapper.findAllWithUser();
// 6. 打印結(jié)果
result.forEach(System.out::println);
sqlSession.close();
resourceAsStream.close();
}
}
總結(jié)
- 編寫實體類
- 編寫對應(yīng)的mapper接口
- 編寫對應(yīng)的SQL語句和映射結(jié)果
- 測試
4.2 一對多查詢
查詢所有用戶的對應(yīng)的用戶訂單表
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 標簽進行關(guān)聯(lián)
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. 執(zhí)行SQL參數(shù)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查詢
List<User> result = mapper.findAllWithOrder();
// 6. 打印
result.forEach(System.out::println);
// 7. 釋放資源
sqlSession.close();
}
4.3 多對多查詢
查詢所用用戶和對應(yīng)的角色身份
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 測試
/**
* 多對多關(guān)聯(lián)查詢
*
* @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. 執(zhí)行SQL參數(shù)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查詢
List<User> result = mapper.findAllWithRole();
// 6. 打印
result.forEach(System.out::println);
// 7. 釋放資源
sqlSession.close();
}
4.4 本章總結(jié)
在單表或者多表查詢種
- 多對一(一對一)配置:使用resultMap和association標簽做映射配置
- 一對多配置:使用resultMap和collection
- 多對多配置:使用resultMap和collection
- 多對多和一對多很相似,難度在于SQL語句的編寫
5. Mybatis嵌套查詢
什么是嵌套查詢撼泛,就是原本是多表查詢中的聯(lián)合語句拆分成各自的單表查詢挠说,再將他們嵌套起來進行查詢
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. 執(zhí)行查詢
List<Order> result = mapper.findAllAndUser();
// 6. 打印結(jié)果
result.forEach(System.out::println);
sqlSession.close();
resourceAsStream.close();
}
5.1.5 總結(jié)
所謂的嵌套查詢愿题,就是使用association標簽進行調(diào)用其他的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. 執(zhí)行SQL參數(shù)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查詢
List<User> result = mapper.findAllAndOrder();
// 6. 打印
result.forEach(System.out::println);
// 7. 釋放資源
sqlSession.close();
}
5.3 多對多
需求:查詢用戶對應(yīng)的角色身份
5.3.1 SQL語句
# 查詢所有用戶
select * from user
# 根據(jù)用戶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. 執(zhí)行SQL參數(shù)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 5. 查詢
List<User> result = mapper.findAllAndRole();
// 6. 打印
result.forEach(System.out::println);
// 7. 釋放資源
sqlSession.close();
}
5.3.5 總結(jié)
- 一對一配置:使用resultMap + association杆兵,通過column條件,執(zhí)行select查詢
- 一對多配置:使用resultMap + collection仔夺,通過column條件琐脏,執(zhí)行select查詢
- 多對多配置:使用resultMap + collection,通過column條件缸兔,執(zhí)行select查詢
- 優(yōu)點:簡化多表查詢操作
- 缺點:執(zhí)行多次sql語句日裙,浪費數(shù)據(jù)庫性