Mybatis 任务二:配置文件深入
Mybatis 任务二:配置文件深入
课程任务主要内容:
* Mybatis 高级查询* 映射配置文件深入* 核心配置文件深入* Mybatis 多表查询* Mybatis 嵌套查询
一 Mybatis 高级查询
1.1 ResultMap 属性
建立对象关系映射
- resultType:如果实体的属性名与表中字段名一致(前提),将查询结果自动封装到实体类中
- ResultMap:如果实体的属性名与表中字段名不一致,可以使用ResutlMap 实现手动封装到实体类中
- 编写UserMapper 接口
public interface UserMapper {public List<User> findAllResultMap();}
- 编写UserMapper.xml
<!--id:唯一标识此resultMaptype:封装后实体的类型,要使用全类名,当在mybatis核心配置类中起了别名之后,可以使用别名--><resultMap id="userResultMap" type="com.myLagou.entity.User"><!--手动配置映射关系--><!--property用来配置实体类中的属性名,column用来配置数据库表中的字段名 --><!--id:用来配置主键--><id property="id" column="id"></id><!--配置其他属性--><result property="usernameabc" column="username"></result><result property="birthdayabc" column="birthday"></result><result property="sexabc" column="sex"></result><result property="addressabc" column="address"></result>补充:如果有查询结果有 字段与属性是对应的,可以省略手动封装 【了解】</resultMap><!--查询所有用户--><!--ResultMap:如果实体的属性名与表中字段名不一致,可以使用ResultMap 实现手动封装到实体类中--><select id="findAllResultMap" resultMap="userResultMap">select * from user</select>
3)代码测试
//测试resultMap@Testpublic void test2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//当前返回的其实就是基于UserMapper所产生的代理对象,底层就是JDK的动态代理, 实际类型就是一个ProxyList<User> userList = mapper.findAllResultMap();sqlSession.close();for (User user : userList) {System.out.println(user);}}
1.2 多条件查询(三种)
需求
根据id 和username 查询 user 表
User实体类
package com.myLagou.entity;import java.util.Date;/*** @author zhy* @create 2022-08-07 14:11*/
public class User {private Integer id;private String usernameabc;private Date birthdayabc;private String sexabc;private String addressabc;public User() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsernameabc() {return usernameabc;}public void setUsernameabc(String usernameabc) {this.usernameabc = usernameabc;}public Date getBirthdayabc() {return birthdayabc;}public void setBirthdayabc(Date birthdayabc) {this.birthdayabc = birthdayabc;}public String getSexabc() {return sexabc;}public void setSexabc(String sexabc) {this.sexabc = sexabc;}public String getAddressabc() {return addressabc;}public void setAddressabc(String addressabc) {this.addressabc = addressabc;}@Overridepublic String toString() {return "User{" +"id=" + id +", usernameabc='" + usernameabc + '\'' +", birthdayabc=" + birthdayabc +", sexabc='" + sexabc + '\'' +", addressabc='" + addressabc + '\'' +'}';}
}
1)方式一
使用 #{arg0}-#{argn} 或者 #{param1}-#{paramn} 获取参数
UserMapper 接口
public interface UserMapper {public List<User> findByIdAndUsername1(Integer id, String username);}
UserMapper.xml
<!--多条件查询方式1--><!--当有多个参数时,占位符#{}与参数之间的匹配关系为:#{arge0}对应第一个参数,#{arge1}对应第二个参数,依此类推-->
<!-- <select id="findByIdAndUsername1" resultMap="userResultMap">-->
<!-- select * from user where id = #{arg0} and username = #{arg1}-->
<!-- </select>--><!--当有多个参数时,占位符#{}与参数之间的匹配关系为:#{param1}对应第一个参数,#{param2}对应第二个参数,依此类推--><select id="findByIdAndUsername1" resultMap="userResultMap">select * from user where id = #{param1} and username = #{param2}</select>
测试
//测试多条件查询方式1@Testpublic void test3() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//当前返回的其实就是基于UserMapper所产生的代理对象,底层就是JDK的动态代理, 实际类型就是一个ProxyList<User> username1 = mapper.findByIdAndUsername1(1, "子慕");sqlSession.close();for (User user : username1) {System.out.println(user);}}
2)方式二
使用注解,引入 @Param() 注解获取参数
UserMapper 接口
/*多条件查询方式2*/public List<User> findByIdAndUsername2(@Param("id") Integer id, @Param("username")String username);
UserMapper.xml
<!--多条件查询方式2在接口中的方法参数位置使用@Param("xxx"),在select语句中的占位符#{}中使用param声明的xxx来匹配参数--><select id="findByIdAndUsername2" resultMap="userResultMap">select * from user where id = #{id} and username = #{username}</select>
测试
//测试多条件查询方式2@Testpublic void test4() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//当前返回的其实就是基于UserMapper所产生的代理对象,底层就是JDK的动态代理, 实际类型就是一个ProxyList<User> username1 = mapper.findByIdAndUsername2(1, "子慕");sqlSession.close();for (User user : username1) {System.out.println(user);}}
3)方式三(推荐)
使用pojo 对象传递参数
UserMapper 接口
/*多条件查询方式3*/public List<User> findByIdAndUsername3(User user);
UserMapper.xml
<!--多条件查询方式3使用整个实体对象来做参数占位符#{}中所写的参数要与实体类中的属性名一致--><select id="findByIdAndUsername3" resultMap="userResultMap" parameterType="User">select * from user where id = #{id} and username = #{usernameabc}</select>
测试
//测试多条件查询方式3@Testpublic void test5() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//当前返回的其实就是基于UserMapper所产生的代理对象,底层就是JDK的动态代理, 实际类型就是一个ProxyUser user1 = new User();user1.setId(1);user1.setUsernameabc("子慕");List<User> username1 = mapper.findByIdAndUsername3(user1);sqlSession.close();for (User user : username1) {System.out.println(user);}}
1.3 模糊查询
需求
根据username 模糊查询user 表
1)方式一
使用#{}占位符
UserMapper 接口
/*模糊查询方式1*/public List<User> findByUsername1(String username);
UserMapper.xml
<!--模糊查询方式1--><!--当所传递参数parameterType为基本数据类型或者是String类型,且传递参数只有一个时,那么#{}中的参数随便写,但是一般遵循见名知意原则--><select id="findByUsername1" resultMap="userResultMap" parameterType="String">select * from user where username like #{username}</select><!--#{}在进行实际参数的转换的时候,替换真正的参数值时会自动的帮我们添加上单引号-->
测试
//测试多模糊查询方式1@Testpublic void test6() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//findByUsername1("子慕")如果只写成这样,那么就相对于等值查询,只会查出username=子慕的数据,而不是模糊查询//要想是模糊查询,就需要添加上通配符%,如下所示:List<User> username1 = mapper.findByUsername1("%子慕%");sqlSession.close();for (User user : username1) {System.out.println(user);}}
2)方式二
使用${},进行sql原样拼接
UserMapper 接口
public interface UserMapper {/*模糊查询方式2*/public List<User> findByUsername2(String username);
}
UserMapper.xml
<!--模糊查询方式2 使用${}占位符--><!--当所传递参数parameterType为基本数据类型或者是String类型,且传递参数只有一个时,那么${}中的值只能写value--><select id="findByUsername2" resultMap="userResultMap" parameterType="String">select * from user where username like '${value }'</select><!--${}实际上是进行sql原样拼接,不会替换真正的参数值时不会自动的加上单引号,所以需要我们自己手动添加-->
测试
//测试多模糊查询方式2@Testpublic void test7() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> username1 = mapper.findByUsername2("%子慕%");sqlSession.close();for (User user : username1) {System.out.println(user);}}
3)方式三
UserMapper 接口
public interface UserMapper {public List<User> findByUsername3(String username);}
UserMapper.xml
<mapper namespace="com.lagou.mapper.UserMapper"><!--不推荐使用,因为会出现sql 注入问题--><select id="findByUsername3" parameterType="string" resultType="user">select * from user where username like '%${value}%'</select></mapper>
测试
//测试 模糊查询方式3@Testpublic void testFindByUsername3() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//在sql语句中添加了通配符后再下面的代码中就不需要了,如下所示:List<User> username1 = mapper.findByUsername3("子慕");sqlSession.close();for (User user : username1) {System.out.println(user);}}
4)方式四(推荐)
UserMapper 接口
public interface UserMapper {public List<User> findByUsername4(String username);}
UserMapper.xml
<!--/*模糊查询方式4*/--><select id="findByUsername4" resultMap="userResultMap" parameterType="String"><!--推荐使用,concat() 字符串拼接函数注意:在 Oracle 中,concat() 函数只能传递二次参数,我们解决方案是嵌套拼接-->select * from user where username like concat(concat('%',#{username}),'%');</select>
测试
//测试 模糊查询方式4@Testpublic void testFindByUsername4() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//在sql语句中添加了通配符后再下面的代码中就不需要了,如下所示:List<User> username1 = mapper.findByUsername4("子慕");sqlSession.close();for (User user : username1) {System.out.println(user);}}
5)${} 与 #{} 区别【面试题】
#{} :表示一个占位符号
通过#{} 可以实现 preparedStatement(预编译对象) 向占位符中设置值,自动进行 java 类型(实体中属性的类型)和 jdbc 类型(表中字段类型)转换,#{}可以有效防止sql 注入。
#{} 可以接收简单类型值或 pojo 属性值。
如果 parameterType 传输单个简单类型值, #{} 括号中可以是value 或其它名称。
${} :表示拼接sql 串
通过${} 可以将 parameterType 传入的内容拼接在 sql 中且不进行jdbc 类型转换,会出现 sql 注入问题。
${} 可以接收简单类型值或 pojo 属性值。
如果 parameterType 传输单个简单类型值, ${} 括号中只能是value。
- 补充:TextSqlNode.java 源码可以证明
二 Mybatis 映射文件深入
2.1 返回主键
应用场景
我们很多时候有这种需求,向数据库插入一条记录后,希望能立即拿到这条记录在数据库中的主键值。
2.1.1 useGeneratedKeys
UserMapper接口
public interface UserMapper {// 返回主键public void save(User user);}
UserMapper.xml
<!--添加用户并且获取返回主键的值,方式1--><!--useGeneratedKeys:声明返回主键,值为true表示返回,值为false表示不返回keyProperty:把返回的主键的值封装到实体中的指定的属性上--><insert id="saveUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})</insert>
注意:只适用于主键自增的数据库,mysql 和sqlserver 支持,oracle 不行。
测试
//测试添加用户并且获取返回主键的值,方式1@Testpublic void test8() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = new User();user1.setUsername("杨洋");user1.setBirthday(new Date());user1.setSex("男");user1.setAddress("我心里");System.out.println(user1);//user1的id为nullmapper.saveUser(user1);sqlSession.commit();sqlSession.close();System.out.println(user1);//user1的id有值}
2.1.2 selectKey
UserMapper接口
public interface UserMapper {// 返回主键public void save(User user);}
UserMapper.xml
<!--添加用户并且获取返回主键的值,方式1--><!--selectKey:获取返回指定的主键值,适用范围广,支持所有类型数据库order="AFTER":表示selectKey中的语句在执行sql语句之后执行(在MySQL、SQL Server数据库中是使用after,但是在oracle数据库中使用的是beforekeyColumn:指定主键对应数据库表中对应的列名keyProperty:指定主键封装到实体的 指定 属性中resultType:指定主键类型--><insert id="saveUser2" parameterType="user"><selectKey order="AFTER" keyColumn="id" keyProperty="id" resultType="int">SELECT LAST_INSERT_ID();</selectKey>insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})</insert>
测试
//测试添加用户并且获取返回主键的值,方式2@Testpublic void test9() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = new User();user1.setUsername("于途");user1.setBirthday(new Date());user1.setSex("男");user1.setAddress("我心里");System.out.println(user1);//user1的id为nullmapper.saveUser2(user1);sqlSession.commit();sqlSession.close();System.out.println(user1);//user1的id有值}
2.2 动态 SQL
应用场景
当我们要根据不同的条件,来执行不同的 sql 语句的时候,需要用到动态sql。
2.2.1 动态 SQL 之<if>标签
需求
根据id 和username 查询,但是不确定两个都有值。
a)UserMapper 接口
public List<User> findByIdAndUsernameIf(User user);
b)UserMapper.xml 映射
<!--动态sql的if标签:多条件查询--><!-- /*test里面写的就是表达式*//*#{}中的值也需要跟传递过来的parameterType实体类中的属性名一样*/-->
<!-- <select id="findByIdAndUsernameIf" parameterType="user" resultMap="userResultMap">-->
<!-- select * from user where 1=1-->
<!-- <if test="id != null">-->
<!-- and id = #{id}-->
<!-- </if>-->
<!-- <if test="username != null">-->
<!-- and username = #{username}-->
<!-- </if>-->
<!-- </select>--><!--根据上述select查询语句中的where 1=1 可以直接改写为如下代码下述代码中的<where>标签就相对于where 1=1,但是如果没有条件的话,不会拼接上where关键字,只有有条件的时候才会自动拼接上--><select id="findByIdAndUsernameIf" parameterType="user" resultMap="userResultMap">select * from user<where><if test="id != null">and id = #{id}</if><if test="username != null">and username = #{username}</if></where></select>
c)测试代码
//测试 动态sql的if标签:多条件查询@Testpublic void tes10() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = new User();//user1.setUsername("杨洋");//只有username时可以查询出
// user1.setId(1);//只有id值的时候也可以查出user1.setId(1);user1.setUsername("子慕");//id和username都有的时候也可以查出List<User> userList = mapper.findByIdAndUsernameIf(user1);sqlSession.close();for (User user : userList) {System.out.println(user);}}
2.2.2 动态 SQL 之标签
需求
如果有id 只使用id 做查询,没有 id 的话看是否有username,有username 就根据username 做查询,如果都没有,就不带条件。
a)UserMapper 接口
public List<User> findByIdAndUsernameChoose(User user);
b)UserMapper.xml 映射
c)测试代码
2.2.3 动态 SQL 之<set>标签
需求
动态更新user 表数据,如果该属性有值就更新,没有值不做处理。
a)UserMapper 接口
//动态sql的set标签:动态更新public void updateIf(User user);
b)UserMapper.xml 映射
<!--//动态sql的set标签:动态更新--><update id="updateIf" parameterType="user">update user<!--<set>标签:在更新的时候,会自动的添加set关键字,还会去掉最后一个条件的逗号,代替了之前直接硬编码的update语句--><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>
c)测试代码
//测试 动态sql的set标签:动态更新@Testpublic void tesUpdateIf() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = new User();user1.setId(10);user1.setUsername("杨洋内娱第一帅哥");user1.setAddress("住在我心坎里!!!");mapper.updateIf(user1);sqlSession.commit();sqlSession.close();System.out.println(user1);}
2.2.4 动态 SQL 之<foreach>标签
foreach 主要是用来做数据的循环遍历
例如:select * from user where id in (1,2,3) 在这样的语句中,传入的参数部分必须依靠foreach 遍历才能实现。
- <foreach>标签用于遍历集合,它的属性:
- collection:代表要遍历的集合元素
- open:代表语句的开始部分
- close:代表结束部分
- item:代表遍历集合的每个元素,生成的变量名
- sperator:代表分隔符
a)当传递参数的容器为集合类型
UserMapper 接口
/*动态sql的foreach标签:多值查询,*/public List<User> findByList(List<Integer> ids);
UserMaper.xml 映射
<!--动态sql的foreach标签:多值查询,根据多个id值查询用户,多个id组成一个集合--><select id="findByList" parameterType="list" resultType="user"><!--原始的sql语句:select * from user id in(1,2,3)--><!--使用动态sql语句如下-->select * from user<where><!--collection:代表要遍历的集合元素,当要遍历的集合为普通类型(如基本数据类型或者String)collection 属性值就可以写:collection 或者 listopen:代表foreach中语句开始的部分close:代表foreach中语句结束的部分item:代表遍历集合中的每个元素生成的变量名separator:分隔符,将item中的变量进行分隔#{}中所写的值要与item所写的值一致--><foreach collection="collection" open="id in (" close=")" item="id" separator=",">#{id}</foreach></where></select>
测试代码
//测试 动态sql的foreach标签:多值查询,根据多个id值查询用户,多个id组成一个集合@Testpublic void tesFindByList() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<Integer> list = new ArrayList<>();list.add(1);list.add(10);list.add(11);List<User> userByList = mapper.findByList(list);for (User user : userByList) {System.out.println(user);}}
b)当传递参数的容器为数组类型
UserMapper 接口
/*动态sql的foreach标签:多值查询,多值组成一个数组时*/public List<User> findByArray(Integer[] ids);
UserMaper.xml 映射
<!--动态sql的foreach标签:多值查询,根据多个id值查询用户,多个id组成一个数组--><select id="findByArray" parameterType="int" resultType="user">select * from user<where><!--collection:代表要遍历的数组元素,collection 属性值就可以写:arrayopen:代表foreach中语句开始的部分close:代表foreach中语句结束的部分item:代表遍历集合中的每个元素生成的变量名separator:分隔符,将item中的变量进行分隔#{}中所写的值要与item所写的值一致--><foreach collection="array" open="id in (" close=")" item="id" separator=",">#{id}</foreach></where></select>
测试代码
//测试 动态sql的foreach标签:多值查询,根据多个id值查询用户,多个id组成一个数组@Testpublic void tesFindByArray() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);Integer[] ids = {1,10,11};List<User> userArray = mapper.findByArray(ids);for (User user : userArray) {System.out.println(user);}}
c)pojo
QueryVo
public class QueryVo {private List<Integer> ids;
}
核心配置文件
<!--设置实体别名-->
<typeAliases><typeAlias type="com.lagou.domain.User" alias="user"></typeAlias><typeAlias type="com.lagou.domain.QueryVo" alias="queryVo"></typeAlias></typeAliases>
UserMapper 接口
public List<User> findByPojo(QueryVo queryVo);
UserMaper.xml 映射
<!--
如果查询条件为复杂类型pojo 对象,collection 属性值为:集合或数组的属性名
--><select id="findByPojo" parameterType="queryVo" resultType="user">SELECT * FROM `user`<where><foreach collection="ids" open="id in(" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
测试代码
// foreach 标签 pojo
@Test
public void testFindByPojo() throws Exception {UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<Integer> ids = new ArrayList<>();ids.add(46);ids.add(48);ids.add(51);QueryVo queryVo = new QueryVo();queryVo.setIds(ids);List<User> list = userMapper.findByPojo(queryVo);System.out.println(list);
}
2.3 SQL 片段
应用场景
映射文件中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<!--在于CRUD操作的同级下,使用<sql>标签进行重复代码的抽取-->
<!--抽取重复的sql代码--><sql id="selectUser">select * from user</sql>
<!--动态sql的foreach标签:多值查询,根据多个id值查询用户,多个id组成一个集合--><select id="findByList" parameterType="list" resultType="User"><!--引入被抽取的sql语句--><include refid="selectUser"></include><where><foreach collection="collection" open="id in (" close=")" item="id" separator=",">#{id}</foreach></where></select>
2.4 知识小结
MyBatis 映射文件配置
<select>:查询
<insert>:插入
<update>:修改
<delete>:删除
<selectKey>:返回主键
<where>:where 条件
<if>:if 判断
<foreach>:for 循环
<set>:set 设置
<sql>:sql 片段抽取
三 Mybatis 核心配置文件深入
3.1 plugins 标签
MyBatis 可以使用第三方的插件来对功能进行扩展,分页助手PageHelper 是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
①导入通用PageHelper 的坐标
②在mybatis 核心配置文件中配置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 插件
<plugins><!--配置分页--><plugin interceptor="com.github.pagehelper.PageHelper"><!--dialect:指定方言,也就是说明整个分页需要支持指定数据库的特有语法--><property name="dialect" value="mysql"/></plugin></plugins>
③测试分页代码实现
//测试 分页助手//核心配置文件深入,plugin标签配置pageHelper@Testpublic void tesPageHelper() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//要想把查询结果分页展示,就需要在查询之前,先设置分页参数//设置分页参数/*startPage(参数1(表示当前页),参数2(表示每页显示的条数)) */PageHelper.startPage(2, 2);List<User> userList = mapper.findAllResultMap();//获取所有用户for (User user : userList) {System.out.println(user);}//获取分页相关的其他数据PageInfo<User> userPageInfo = new PageInfo<User>(userList);//将查询出来的结果集作为参数传入//PageInfo就会根据传入的参数去计算分页的总条数,分页数等等System.out.println("总条数:" + userPageInfo.getTotal());System.out.println("总页数:" + userPageInfo.getPages());System.out.println("当前页:" + userPageInfo.getPageNum());System.out.println("是否是第一页:" + userPageInfo.isIsFirstPage());sqlSession.close();}
3.2 知识小结
MyBatis 核心配置文件常用标签:
1、properties 标签:该标签可以加载外部的 properties 文件
2、typeAliases 标签:设置类型别名
3、environments 标签:数据源环境配置标签
4、plugins 标签:配置MyBatis 的插件(可以自定义插件,也可以整合其他第三方插件)
四 Mybatis 多表查询
4.1 数据库表关系介绍
关系型数据库表关系分为
- 一对一
一对多
多对多
举例
人和身份证号就是一对一
- 一个人只能有一个身份证号
- 一个身份证号只能属于一个人
用户和订单就是一对多,订单和用户就是多对一
- 一个用户可以下多个订单
- 多个订单属于同一个用户
学生和课程就是多对多
- 一个学生可以选修多门课程
- 一个课程可以被多个学生选修
特例
- 一个订单只从属于一个用户,所以mybatis 将多对一看成了一对一
案例数据库环境准备
- 创建orders表
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;
往rders表中插入数据
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');
创建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;
往sys_role表中插入数据
INSERT INTO `sys_role` VALUES ('1', 'CTO', 'CTO');INSERT INTO `sys_role` VALUES ('2', 'CEO', 'CEO');
创建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 `user` (`id`),CONSTRAINT `sys_user_role_ibfk_2` FOREIGN KEY (`roleid`) REFERENCES `sys_role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
往 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');
4.2 一对一(多对一)multitable
4.2.1 介绍
一对一查询模型
用户表和订单表的关系为,一个用户有多个订单(一对多的关系),一个订单只从属于一个用户(一对一的关系)
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
一对一查询语句
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
查询结果
- 结果的封装 需要自己手动配置resultMap
4.2.2 代码实现
1 )Order 实体
package com.myLagou.entity;import java.util.Date;/*** @author zhy* @create 2022-08-09 13:40*/
public class Orders {private Integer id;private Date ordertime;private double total;private Integer uid;// 表示当前订单属于哪个用户private User user;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Date getOrdertime() {return ordertime;}public void setOrdertime(Date ordertime) {this.ordertime = ordertime;}public double getTotal() {return total;}public void setTotal(double total) {this.total = total;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}@Overridepublic String toString() {return "Orders{" +"id=" + id +", ordertime=" + ordertime +", total=" + total +", uid=" + uid +", user=" + user +'}';}
}
2 )OrderMapper 接口
public interface OrderMapper {/*一对一关联查询:查询所有的订单,并且查出每个订单所属的用户信息*/public List<Orders> findAllWithUser();
}
3 )OrderMapper.xml 映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!---->
<mapper namespace="com.myLagou.mapper.OrderMapper"><resultMap id="orderMap" type="com.myLagou.entity.Orders"><!--配置Orders类真的主键--><id property="id" column="id"></id><!--配置其他属性--><result property="ordertime" column="ordertime"></result><result property="total" column="total"></result><result property="uid" column="uid"></result><!--配置Orders类中的User对象属性--><!--association:在进行一对一关联查询配置时进行类中的对象属性的配置property配置Orders类中要封装的关联对象user属性javaType配置要封装的user的类型 --><association property="user" javaType="com.myLagou.entity.User"><!--在配置user类的column时要注意避免与Orders类中的column混淆,因为orders表中的外键uid就是拿user表的主键id来设置的,所以为了避免id混淆,可以直接拿uid来使用--><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><!-- /*一对一关联查询:查询所有的订单,并且查出每个订单所属的用户信息*/--><!--因为这查询返回的结果为Orders的一个集合,且Orders类中包含了User的信息,mybatis不能直接自动映射封装,所有需要自己手动配置resultMap--><select id="findAllWithUser" resultMap="orderMap">SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;</select>
</mapper>
4 )测试代码
package com.myLagou.test;import com.myLagou.entity.Orders;
import com.myLagou.entity.User;
import com.myLagou.mapper.OrderMapper;
import com.myLagou.mapper.UserMapper;
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 zhy* @create 2022-08-09 14:21*/
public class mybatisTest {/*一对一关联查询:查询所有的订单,并且查出每个订单所属的用户信息*/@Testpublic void testFindAllWithUser() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);List<Orders> ordersList = mapper.findAllWithUser();for (Orders orders : ordersList) {System.out.println(orders);}sqlSession.close();}
}
4.3 一对多
4.3.1 介绍
一对多查询模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单(从用户的角度来看是一对多)
一对多查询语句
SELECT u.*, o.id oid, o.ordertime,o.total, o.uid FROM orders o RIGHT JOIN user u ON u.`id` = o.`uid`;
查询结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p62ktvoc-1660055717105)(D:\blog\Notes\lagou\SSM\Mybatis\任务二\Mybatis 任务二:配置文件深入.assets\查询结果2.png)]
4.3.2 代码实现
1 )User 实体
package com.myLagou.entity;import java.util.Date;
import java.util.List;/*** @author zhy* @create 2022-08-07 14:11*/
public class User {private Integer id;private String username;private Date birthday;private String sex;private String address;//表示一对多中多的那一方的关系使用集合// 代表当前用户具备的订单列表private List<Orders> orderList;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public List<Orders> getOrderList() {return orderList;}public void setOrderList(List<Orders> orderList) {this.orderList = orderList;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", birthday=" + birthday +", sex='" + sex + '\'' +", address='" + address + '\'' +", orderList=" + orderList +'}';}
}
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 代表当前用户具备的订单列表
private List orderList;
}
2 )UserMapper 接口
public interface UserMapper {/*一对多查询的需求:查询所有用户,与此同时查询出该用户具有的订单信息*/public List<User> findAllWithOrder();}
3 )UserMapper.xml 映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.myLagou.mapper.UserMapper"><resultMap id="userMapper" type="com.myLagou.entity.User"><!--为了避免出现id混淆,就sql语句执行的时候给orders表的id起别名,所以此处就使用id即可--><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:一对多的查询时,使用 collection 标签关联property="orderList" 封装到集合的属性名ofType="order" 封装集合的泛型类型--><collection property="orderList" ofType="com.myLagou.entity.Orders"><!--配置Orders类的主键--><id property="id" column="oid"></id><!--配置其他属性--><result property="ordertime" column="ordertime"></result><result property="total" column="total"></result><result property="uid" column="uid"></result></collection></resultMap><!--/*一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单信息*/--><select id="findAllWithOrder" resultMap="userMapper">SELECT u.*, o.id oid, o.ordertime,o.total, o.uid FROM orders o RIGHT JOIN user u ON u.`id` = o.`uid`;</select>
</mapper>
4 )测试代码
/*一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单信息*/@Testpublic void testFindAllWithOrder() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.findAllWithOrder();for (User user : userList) {System.out.println(user);}sqlSession.close();}
4.4 多对多
4.4.1 介绍
多对多查询的模型
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
多对多查询语句
- 先分开查询 先查出所有的用户的id对应的roleid
- 将上述查询结果当作一张虚拟表再去与用户角色role表进行关联查询
- 最终的sql语句为:
select u.*, r.id rid, r.rolename, r.roleDesc from user u left join sys_user_role ur on ur.userid = u.idleft join sys_role r on ur.roleid = r.id;
4.4.2 代码实现
1 )User 和Role 实体
User实体类
package com.myLagou.entity;import java.util.Date;import java.util.List;/*** @author zhy* @create 2022-08-07 14:11*/
public class User {private Integer id;private String username;private Date birthday;private String sex;private String address;//表示一对多中多的那一方的关系使用集合// 代表当前用户具备的订单列表private List<Orders> orderList;// 代表当前用户关联的角色列表private List<Role> roleList;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public List<Orders> getOrderList() {return orderList;}public void setOrderList(List<Orders> orderList) {this.orderList = orderList;}public List<Role> getRoleList() {return roleList;}public void setRoleList(List<Role> roleList) {this.roleList = roleList;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", birthday=" + birthday +", sex='" + sex + '\'' +", address='" + address + '\'' +", orderList=" + orderList +", roleList=" + roleList +'}';}
}
Role实体类
package com.myLagou.entity;/*** @author zhy* @create 2022-08-09 15:38*/
public class Role {private Integer id;private String rolename;private String roleDesc;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getRolename() {return rolename;}public void setRolename(String rolename) {this.rolename = rolename;}public String getRoleDesc() {return roleDesc;}public void setRoleDesc(String roleDesc) {this.roleDesc = roleDesc;}@Overridepublic String toString() {return "Role{" +"id=" + id +", rolename='" + rolename + '\'' +", roleDesc='" + roleDesc + '\'' +'}';}
}
2 )UserMapper 接口
public interface UserMapper {/*多对多关联查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/public List<User> findAllWithRole();
}
3 )UserMapper.xml 映射
<!--多对多的resultMap配置--><!--要封装到user实体类上,所以type为user--><resultMap id="userRoleMap" type="com.myLagou.entity.User"><!--设置User表中的主键id--><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.myLagou.entity.Role"><!--配置Role类的主键--><id property="id" column="rid"></id><!--配置其他属性--><result property="rolename" column="rolename"></result><result property="roleDesc" column="roleDesc"></result></collection></resultMap><!--/*多对多关联查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/--><select id="findAllWithRole" resultMap="userRoleMap">select u.*, r.id rid, r.rolename, r.roleDesc from user uleft join sys_user_role ur on ur.userid = u.idleft join sys_role r on ur.roleid = r.id;</select>
4 )测试代码
/*多对多关联查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/@Testpublic void testFindAllWithRole() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();/*mapper要调用的方法在哪个XxxMapper中,就使用哪个类,所以使用UserMapper.class*/UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> allWithRole = mapper.findAllWithRole();for (User user : allWithRole) {System.out.println(user);}sqlSession.close();}
public void testUserWithRole() throws Exception {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List list = userMapper.findAllWithRole();
for (User user : list) {
System.out.println(user);
}
}
4.5 小结
MyBatis 多表关联配置方式
* 一对一配置:使用<resultMap>+<association>做配置
* 一对多配置:使用<resultMap>+<collection>做配置
* 多对多配置:使用<resultMap>+<collection>做配置
* 多对多的配置跟一对多很相似,难度在于SQL 语句的编写。
五 MyBatis 嵌套查询
5.1 什么是嵌套查询
嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用 mybatis 的语法嵌套在一起。
举个栗子
* 需求:查询一个订单,与此同时查询出该订单所属的用户1. 联合查询
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;2. 嵌套查询2.1 先查询订单SELECT * FROM orders2.2 再根据订单uid 外键,查询用户SELECT * FROM `user` WHERE id = #{根据订单查询的 uid}2.3 最后使用mybatis,将以上二步嵌套起来...
5.2 一对一嵌套查询
5.2.1 介绍
需求:查询一个订单,与此同时查询出该订单所属的用户
一对一查询语句
-- 先查询订单
SELECT * FROM orders;-- 再根据订单 uid 外键,查询用户
SELECT * FROM `user` WHERE id = #{订单的uid};
5.2.2 代码实现
1) OrderMapper 接口
public interface OrderMapper {/*一对一嵌套查询:查询所有的订单,并且查出每个订单所属的用户信息*/public List<Orders> findAllWithUser2();}
2) OrderMapper.xml 映射
<resultMap id="orderMap2" type="com.myLagou.entity.Orders"><!--配置Orders类真的主键--><id property="id" column="id"></id><!--配置其他属性--><result property="ordertime" column="ordertime"></result><result property="total" column="total"></result><result property="uid" column="uid"></result><!--存在问题问题1:怎么去执行嵌套的第二条sql? ————通过select属性问题2:在执行第二条sql的时候,如何把第一条sql查询的结果uid作为参数传递给第二条sql ————通过columnselect属性表示引入UserMapper.xml中的findById的查询语句column表示把第一条sql查询出来的uid作为参数传递给第二条sql语句,也就是传给select属性中的sql语句--><association property="user" javaType="com.myLagou.entity.User"select="com.myLagou.mapper.UserMapper.findById" column="uid"></association></resultMap>
<!-- /*一对一嵌套查询:查询所有的订单,并且查出每个订单所属的用户信息*/--><select id="findAllWithUser2" resultMap="orderMap2">select * from orders</select>
编写完OrderMapper这部分内容后,就把需要嵌套的第二条sql语句需要的代码编写到UserMapper部分中去,在OrderMapper.xml文件中通过association标签中的属性select来从UserMapper.xml中引入sql,使用column将第一条sql查询出来的uid当作结果传递给select属性
3) UserMapper 接口
public interface UserMapper {//为了实现一对一嵌套查询/*根据id查询用户*/public User findById(Integer id);
}
4) UserMapper.xml 映射
<!--/*根据id查询用户*/--><select id="findById" resultType="user" parameterType="int">select * from user where id = #{id}</select>
5)测试代码
/*一对一嵌套查询:查询所有的订单,并且查出每个订单所属的用户信息*/@Testpublic void testFindAllWithUser2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();/*mapper要调用的方法在哪个XxxMapper中,就使用哪个类,所以使用UserMapper.class*/OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);List<Orders> ordersList = mapper.findAllWithUser2();for (Orders orders : ordersList) {System.out.println(orders);}sqlSession.close();}
5.3 一对多嵌套查询
5.3.1 介绍
需求:查询一个用户,与此同时查询出该用户具有的订单
一对多查询语句
-- 先查询用户
SELECT * FROM `user`;-- 再根据用户 id 主键,查询订单列表
SELECT * FROM orders where uid = #{用户 id};
5.3.2 代码实现
a)UserMapper 接口
public interface UserMapper {/*一对多嵌套查询的需求:查询所有用户,与此同时查询出该用户具有的订单信息*/public List<User> findAllWithOrder2();}
b)UserMapper.xml 映射
<!--一对多的嵌套查询--><resultMap id="userOrderMap" type="com.myLagou.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><!--配置的select与column与之前一对一嵌套查询的作用一样--><collection property="orderList" ofType="com.myLagou.entity.Orders" column="id"select="com.myLagou.mapper.OrderMapper.findAllByUid"></collection></resultMap><!-- /*一对多嵌套查询的需求:查询所有用户,与此同时查询出该用户具有的订单信息*/--><select id="findAllWithOrder2" resultMap="userOrderMap">select * from user ;</select>
c)OrderMapper*接口
public interface OrderMapper {/*根据uid查询该用户对应的所有订单*/public List<Orders> findAllByUid(Integer id);}
d)OrderMapper.xml映射
<!-- /*根据uid查询该用户对应的所有订单*/--><select id="findAllByUid" parameterType="int" resultType="com.myLagou.entity.Orders">select * from orders where uid = #{uid}</select>
e)测试代码
/*一对多嵌套查询的需求:查询所有用户,与此同时查询出该用户具有的订单信息*/@Testpublic void testFindAllWithOrder2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();/*mapper要调用的方法在哪个XxxMapper中,就使用哪个类,所以使用UserMapper.class*/UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.findAllWithOrder2();for (User user : userList) {System.out.println(user);}sqlSession.close();}
5.4 多对多嵌套查询
5.4.1 介绍
需求:查询用户同时查询出该用户的所有角色
多对多查询语句
-- 先查询用户
SELECT * FROM `user`;-- 再根据用户 id 主键,查询角色列表
SELECT * FROM role r INNER JOIN user_role ur ON r.`id` = ur.`rid`
WHERE ur.`uid` = #{用户 id};
5.4.2 代码实现
a) UserMapper 接口
public interface UserMapper {/*多对多嵌套查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/public List<User> findAllWithRole2();}
b)UserMapper.xml 映射
<!--多对多嵌套查询--><resultMap id="userRole" type="com.myLagou.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.myLagou.entity.Role" column="id"select="com.myLagou.mapper.RoleMapper.findByUid"></collection></resultMap><!-- /*多对多嵌套查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/--><select id="findAllWithRole2" resultMap="userRole">select * from user</select>
c) RoleMapper 接口
public interface RoleMapper {/*根据用户id来查询对应的角色*/public List<Role> findByUid(Integer uid);}
d) RoleMapper.xml 映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.myLagou.mapper.RoleMapper"><!--/*根据用户id来查询对应的角色*/public List<Role> findByUid(Integer uid);当方法传递的参数为基本数据类型或者为String,且只有一个参数时,parameterType可以省略不写--><select id="findByUid" resultType="role" >select * from sys_role r inner join sys_user_role ur on ur.roleid = r.idwhere ur.userid = #{uid}</select>
</mapper>
e)测试代码
/*多对多嵌套查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/@Testpublic void testFindAllWithRole2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();/*mapper要调用的方法在哪个XxxMapper中,就使用哪个类,所以使用UserMapper.class*/UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.findAllWithRole2();for (User user : userList) {System.out.println(user);}sqlSession.close();}
5.5 小结
一对一配置:使用<resultMap>+<association>做配置,通过column 条件,执行 select 查询
一对多配置:使用<resultMap>+<collection>做配置,通过column 条件,执行 select 查询
多对多配置:使用<resultMap>+<collection>做配置,通过column 条件,执行 select 查询
优点:简化多表查询操作
有的角色信息*/
public List findAllWithRole2();
}
**b)UserMapper.xml** **映射**```xml
<!--多对多嵌套查询--><resultMap id="userRole" type="com.myLagou.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.myLagou.entity.Role" column="id"select="com.myLagou.mapper.RoleMapper.findByUid"></collection></resultMap><!-- /*多对多嵌套查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/--><select id="findAllWithRole2" resultMap="userRole">select * from user</select>
c) RoleMapper 接口
public interface RoleMapper {/*根据用户id来查询对应的角色*/public List<Role> findByUid(Integer uid);}
d) RoleMapper.xml 映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.myLagou.mapper.RoleMapper"><!--/*根据用户id来查询对应的角色*/public List<Role> findByUid(Integer uid);当方法传递的参数为基本数据类型或者为String,且只有一个参数时,parameterType可以省略不写--><select id="findByUid" resultType="role" >select * from sys_role r inner join sys_user_role ur on ur.roleid = r.idwhere ur.userid = #{uid}</select>
</mapper>
e)测试代码
/*多对多嵌套查询需求:查询所有用户,与此同时查询出该用户具有的角色信息*/@Testpublic void testFindAllWithRole2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();/*mapper要调用的方法在哪个XxxMapper中,就使用哪个类,所以使用UserMapper.class*/UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.findAllWithRole2();for (User user : userList) {System.out.println(user);}sqlSession.close();}
5.5 小结
一对一配置:使用<resultMap>+<association>做配置,通过column 条件,执行 select 查询
一对多配置:使用<resultMap>+<collection>做配置,通过column 条件,执行 select 查询
多对多配置:使用<resultMap>+<collection>做配置,通过column 条件,执行 select 查询
优点:简化多表查询操作
缺点:执行多次sql 语句,浪费数据库性能
Mybatis 任务二:配置文件深入相关推荐
- mybatis mysql 配置文件_Mybatis配置文件详解(4)
本次主要来了解: MyBatis数据库配置文件SqlMapConfig.xml SQL映射配置中输入映射的配置 SQL映射配置中输出映射的配置 SQL映射配置中动态SQL语句的配置 1. SqlMap ...
- 【SSM框架系列】Mybatis映射配置文件与核心配置文件深入
传统开发方式Dao层实现 编写UserDao接口 public interface UserDao {List<User> findAll() throws IOException;} 编 ...
- java元婴期(23)----java进阶(mybatis(2)---mapper代理mybatis核心配置文件输入输出映射)
1.mapper代理 1.mybatis开发dao的方法----引入(为啥要使用mapper代理) 1.SqlSession使用范围 1.SqlSessionFactoryBuilder 通过SqlS ...
- Spring+SpringMVC +MyBatis整合配置文件案例66666
Spring+SpringMVC +MyBatis整合配置文件案例 标签: springspringmvcmybatismvcjava 2017-04-13 19:12 228人阅读 评论(1) 收藏 ...
- MyBatis全局配置文件介绍
一.properties properties标签可以用于引入外部的配置文件,也可以用于定义全局变量. 比如我们在配置数据源的时候习惯把相关的信息单独的放在一个配置文件中,方便修改. 数据库配置信息d ...
- mybatis的配置文件中selectKey标签问题
1.mybatis的配置文件中,使用sequence生成主键 未执行add方法之前,主键未生成(null):刚执行add之后,主键即生成(212) 这里的重点是,一旦执行add方法,配置文件中的sel ...
- ssm(Spring+Spring mvc+mybatis)Spring配置文件——applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- MyBatis笔记——配置文件完成增删改查
l 完成品牌数据的增删改查操作 § 要完成的功能列表清单:□ 查询® 查询所有数据® 查看详情® 条件查询□ 添加□ 修改® 修改全部字段® 修改动态字段□ 删除® 删除一个® 批量删除准备环境:§ ...
- 详解mybatis映射配置文件
一 mybatis 映射文件结构 mybatis映射配置文件存在如下顶级元素,且这些元素按照如下顺序被定义. cache – 给定命名空间的缓存配置. cache-ref – 其他命名空间缓存配置的 ...
最新文章
- Hyperface笔记
- android java 圆角_java – Android:给一个webview圆角?
- redux-form(V7.4.2)笔记(二)
- 论文浅尝 | Doc2EDAG:一种针对中文金融事件抽取的端到端文档级框架
- 仙人掌(cactus)
- PLC编程从入门到精通视频教程【副业学习会】
- catia圆管焊接焊接_CATIA焊接设计实例教程
- 装修行业怎么找精准客户?有那些获客渠道?
- 发明计算机的人的名人名言,16句关于科学家的名言
- android实现拍照、相册选图、裁剪功能,兼容7.0以及小米
- 小菊的语义分割3——数据预处理及像素级分类实现原理
- PHP Class SoapClient not found解决方法
- google登陆失败问题解决
- 计算机二级选择题记忆知识点
- laravel 使用SSH 隧道连接到远程数据库
- 重磅 | 分子生物学与遗传学经典名著——《Lewin基因XII》(中译本)
- [书籍翻译]12周撰写期刊文章 学术出版成功指南——第 6 周:加强结构
- 《Javascript高级程序设计》--读书笔记(二)
- 【元胞自动机】元胞自动机交通流仿真【含Matlab源码 827期】
- quartz定时任务中遇到的坑
热门文章
- Java中双冒号(::)运算操作符
- 电子印章怎么验证真假?
- 如何使用卷积神经网络进行图像处理?
- asp.ne服务器代码显示http://l.longtailvideo.com/download/5/9/logo.png不可用,在Window Server2008 服务器上无法播放MP4媒体问题
- JavaScript 基础知识 - 入门篇(二)
- 跑步戴哪款无线耳机好?适合跑步用的运动耳机分享
- VUE:全局引入.lees文件的CSS变量
- 对于ios7扫描二维码功能的实现
- 用Win32DiskImager写入U盘容量变小,恢复容量方法
- 7步快速下载谷歌GoogleEarth三维地形图