当前位置: 移动技术网 > IT编程>开发语言>Java > Mybatis动态sql、if与where的使用、sql片段、foreach遍历、Mybatis的关联查询一对一、一对多、多对多、Mybatis的延时加载

Mybatis动态sql、if与where的使用、sql片段、foreach遍历、Mybatis的关联查询一对一、一对多、多对多、Mybatis的延时加载

2020年09月29日  | 移动技术网IT编程  | 我要评论
目录第一节 Mybatis的动态SQL1.1 if 和where的使用1.2 SQL片断第一节 Mybatis的动态SQL1.1 if 和where的使用if标签:是作为判断参数来使用的,如果符合条件,就把if标签体内的SQL拼接上,不符合条件就不拼接注意:用if进行判断是否为空时,不仅要判断null,还要判断空字符串’'where标签:会去掉条件中的第一个and符号在UserMapper.java接口中写一个方法在UserMapper.xml中配置sql测试与效果packag



第一节 Mybatis的动态SQL

1.1 if 和where的使用

  • if标签:是作为判断参数来使用的,如果符合条件,就把if标签体内的SQL拼接上,不符合条件就不拼接
  • 注意:用if进行判断是否为空时,不仅要判断null,还要判断空字符串’'
  • where标签:会去掉条件中的第一个and符号
  1. 在UserMapper.java接口中写一个方法
    在这里插入图片描述
  2. 在UserMapper.xml中配置sql
    在这里插入图片描述
  3. 测试与效果
package com.it.test; import com.it.mapper.UserMapper; import com.it.model.User; import com.it.vo.UserQueryVo; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; /**
 * @ClassName Demo02
 * @Author shuyy
 * @Date 2020/9/22
 **/ public class Demo01 { SqlSession sqlSession; @Before public void before() throws IOException { System.out.println("before...获取session"); //1.读取配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory创建SqlSession sqlSession = sessionFactory.openSession(); } @After public void after(){ System.out.println("after...关闭session"); //5.关闭SqlSession sqlSession.close(); } @Test public void test1(){ UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 UserQueryVo queryVo = new UserQueryVo(); User user = new User(); user.setSex("男"); user.setUsername("shu04"); queryVo.setUser(user); List<User> list = userMapper.findUserList(queryVo); System.out.println(list); //sqlSession.commit();//增删改记得提交事务 } } 

在这里插入图片描述
在这里插入图片描述

  1. 如果注释了姓名设置,会查询所有符合性别条件的
    在这里插入图片描述
  2. 如果注释了性别设置,虽然不会报错,但是查询不到结果,这是由于sql所致
    在这里插入图片描述
  3. 为了正确的使用sql,使用if与where来拼接sql,如果要查询的字段值为空,就不把该字段的条件加到sql上,起到动态拼接sql的效果
    在这里插入图片描述
 <!--if与where的使用--><!--查询性别和名字--> <select id="findUserList" parameterType="UserQueryVo" resultType="user"> select * from user <where> <if test="user != null"> <if test="user.sex != null and user.sex != ''"> sex = #{user.sex} </if> <if test="user.username != null and user.username != ''"> and username like '%${user.username}%' </if> </if> </where> </select> 
  1. 注释一些配置的效果,就算注释了设置user,user为空也不报错
    在这里插入图片描述
  2. where会去除条件中第一个and符号(上面的语句中写的是and username like ‘%${user.username}%’),拼接后的语句中去除了and,防止了SQL错误
    在这里插入图片描述
  3. 注释了条件,就不拼接到对应的sql上
    在这里插入图片描述

1.2 SQL片断

  • Mybatis提供了SQL片段的功能,可以提高SQL的可重用性
    在这里插入图片描述
 <!--if与where的使用--><!--查询性别和名字--> <!--声明一个sql片段--> <sql id="select_user_where"> <if test="user != null"> <if test="user.sex != null and user.sex != ''"> sex = #{user.sex} </if> <if test="user.username != null and user.username != ''"> and username like '%${user.username}%' </if> </if> </sql> <select id="findUserList" parameterType="UserQueryVo" resultType="user"> select * from user <where> <!--引用sql片段--> <include refid="select_user_where"/> </where> </select> 
  • 成功执行
    在这里插入图片描述

1.3 foreach遍历

  1. 先在包装类中提供一个List,并提供get/set
    在这里插入图片描述
  2. 在UserMapper.java中提供一个方法
    在这里插入图片描述
  3. 在UserMapper.xml中提供对应的sql
    在这里插入图片描述
 <!--foreach的使用--> <select id="findUserByIds" parameterType="userQueryVo" resultType="user"> select * from user <where> <if test="ids != null and ids.size > 0"> <!--
                    foreach标签:表示一个foreach循环
                    collection:集合参数名称,如果是直接传入集合参数,则该处的参数名称只能填 list
                    item:每次遍历出来的对象
                    open:开始遍历时拼接的串(sql)
                    close:结束遍历时拼接的串(sql)
                    separator:遍历出的每个对象之间需要拼接的字符
                --> <foreach collection="ids" item="id" open="id in (" separator="," close=")"> ${id} </foreach> </if> </where> </select> 
  1. 测试
package com.it.test; import com.it.mapper.UserMapper; import com.it.model.User; import com.it.vo.UserQueryVo; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /**
 * @ClassName Demo02
 * @Author shuyy
 * @Date 2020/9/22
 **/ public class Demo02 { SqlSession sqlSession; @Before public void before() throws IOException { System.out.println("before...获取session"); //1.读取配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory创建SqlSession sqlSession = sessionFactory.openSession(); } @After public void after(){ System.out.println("after...关闭session"); //5.关闭SqlSession sqlSession.close(); } @Test public void test1(){ //通过session获取代理【jdk实现的代理】 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 UserQueryVo queryVo = new UserQueryVo(); List<Integer> ids = new ArrayList<Integer>(); ids.add(34); ids.add(35); ids.add(36); queryVo.setIds(ids); List<User> list = userMapper.findUserByIds(queryVo); for (User user : list) { System.out.println(user); } //sqlSession.commit();//增删改记得提交事务 } } 

在这里插入图片描述
在这里插入图片描述

参数是数组的遍历

  • 发现上面的使用有一些麻烦,直接在参数中传入数组
  1. 在UserMapper.java中提供方法
    在这里插入图片描述
  2. 在UserMapper.xml中提供对应的sql
    在这里插入图片描述
  3. 测试
    在这里插入图片描述

第二节 Mybatis的关联查询

2.1 案例:用户与订单

  • 在day01数据库表的基础上实现
    在这里插入图片描述
  • user和orders:
  1. User 与orders:一个用户可以创建多个订单,一对多
  2. Orders 与 user:多个订单可由一个用户创建,多对一
  • orders和orderdetail:
  1. Orders 与 orderdetail:一个订单可以包括 多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
  2. orderdetail 与orders:多个订单明细包括在一个订单中, 多对一
  • orderdetail和items:
  1. Orderdetail 与 items:多个订单明细只对应一个商品信息,多对一
  2. Items 与 orderdetail:一个商品可以包括在多个订单明细 ,一对多
  • 需求:根据用户id查找订单信息,包括用户名和地址
    在这里插入图片描述
#查找id为1的所有订单 SELECT orders.id, orders.number, orders.createtime, orders.note, USER.username, USER.address FROM orders, USER WHERE orders.user_id = USER.id AND USER.id = 1; 

在这里插入图片描述
在这里插入图片描述

2.2 一对一(resultType实现)

  • 复杂查询时,单表对应的po类已不能满足输出结果集的映射,所以要根据需求建立一个扩展类来作为resultType的类型
  • 例如:查找某个订单id的信息,包括用户名和地址
    在这里插入图片描述
#查找某个订单id的信息,包括用户名和地址 SELECT o.*, u.username, u.address FROM orders o, USER u WHERE o.user_id = u.id AND o.id = 3 
  • 单个orders表的类型已无法满足,所以创建一个扩展类来满足需求

第一步:写一个订单类的扩展类

  • 原来的订单类,提供get/set,toString
    在这里插入图片描述
  • 订单扩展类OrdersExt,提供属性的get/set,toString(在toString中调用父类orders的toString)
    在这里插入图片描述

第二步:声明订单接口

在这里插入图片描述

第三步:声明订单配置文件

在这里插入图片描述

<?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.it.mapper.OrderMapper"> <select id="findOrderById" parameterType="int" resultType="ordersExt"> select
            o.*,u.username,u.address
        from
            orders o,user u
        where
            o.user_id = u.id
        and o.id = #{id} </select> </mapper> 

第四步:加载映射文件

在这里插入图片描述

第五步:测试

package com.it.test; import com.it.mapper.OrderMapper; import com.it.model.OrdersExt; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; /**
 * @ClassName Demo02
 * @Author shuyy
 * @Date 2020/9/22
 **/ public class Demo03 { SqlSession sqlSession; @Before public void before() throws IOException { System.out.println("before...获取session"); //1.读取配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory创建SqlSession sqlSession = sessionFactory.openSession(); } @After public void after(){ System.out.println("after...关闭session"); //5.关闭SqlSession sqlSession.close(); } @Test public void test1(){ //通过session获取代理【jdk实现的代理】 OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 OrdersExt orderById = orderMapper.findOrderById(3); System.out.println(orderById); //sqlSession.commit();//增删改记得提交事务 } } 

在这里插入图片描述

2.3 一对一(resultMap实现)

  • 其实就是在模型里使用模型,association的使用

第一步:在Orders类中添加User模型,并提供get/set

  • User 订单所属的用户
    在这里插入图片描述

第二步:在订单Mapper接口中写一个方法

在这里插入图片描述

第三步:在订单配置文件中配置resultMap

在这里插入图片描述

 <!--如果模型里有模型,使用resultMap--> <resultMap id="ordersResultMap" type="orders"> <!--与orders模型匹配数据--> <id column="id" property="id"></id> <id column="note" property="note"></id> <id column="number" property="number"></id> <id column="createtime" property="createtime"></id> <!--orders的user匹配数据
        模型里有模型,使用association来配置
        --> <association property="user" javaType="user"> <id column="user_id" property="id"></id> <id column="username" property="username"></id> <id column="address" property="address"></id> </association> </resultMap> <select id="findOrderByMap" parameterType="int" resultMap="ordersResultMap"> select
            o.*,u.username,u.address
        from
            orders o,user u
        where
            o.user_id = u.id
        and o.id = #{id} </select> 

第四步:测试

 @Test public void test2(){ //通过session获取代理【jdk实现的代理】 OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 Orders order = orderMapper.findOrderByMap(3); System.out.println(order); System.out.println(order.getUser()); //sqlSession.commit();//增删改记得提交事务 } 

在这里插入图片描述

总结

  • resultType:resultType的使用较为简单,如果pojo中没有包括查询出的列名,可以通过增加对应属性的列名来完成映射。如果对于查询结果没有特殊的要求,建议使用resultType

  • resultMap:需要单独定义resultMap,实现起来有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以将关联查询映射到pojo对象的属性中。

  • resultMap可以实现延迟加载,resultType则无法实现延迟加载。

2.4 一对多(resultMap+collection)

  • 其实就是在模型中使用集合,即collection的使用
  • 例如:根据订单id查找订单信息、用户信息和订单明细信息
    在这里插入图片描述
#根据订单id查找订单信息、用户信息和订单明细信息 SELECT o.*, u.username, u.address, od.id, od.items_id, od.items_num FROM orders o, USER u, orderdetail od WHERE o.user_id = u.id AND o.id = od.orders_id AND o.id = 3 

第一步:写一个订单详情类

在这里插入图片描述

  • 属性与数据库字段对应,并提供get/set,toString
    在这里插入图片描述
package com.it.model; public class OrdersDetail { private Integer id;//订单id private Integer items_id;//商品id private Integer items_num;//商品购买数量 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getItems_id() { return items_id; } public void setItems_id(Integer items_id) { this.items_id = items_id; } public Integer getItems_num() { return items_num; } public void setItems_num(Integer items_num) { this.items_num = items_num; } @Override public String toString() { return "OrdersDetail{" + "id=" + id + ", items_id=" + items_id + ", items_num=" + items_num + '}'; } } 

第二步:Orders中添加订单详情

  • 并提供get/set
    在这里插入图片描述

第三步:OrderMapper接口中写方法

在这里插入图片描述

第四步:OrderMapper.xml中添加配置

在这里插入图片描述

 <!--一对多--> <resultMap id="ordersResultMap2" type="orders"> <!--与orders模型匹配数据--> <id column="id" property="id"></id> <id column="note" property="note"></id> <id column="number" property="number"></id> <id column="createtime" property="createtime"></id> <!--orders的user匹配数据
        模型里有模型,使用association来配置
        --> <association property="user" javaType="user"> <id column="user_id" property="id"></id> <id column="username" property="username"></id> <id column="address" property="address"></id> </association> <!--一对多匹配集合:往orders的orderDetails 匹配数据
        注意:集合里类型使用ofType,而不是javaType
        --> <collection property="ordersDetailList" ofType="ordersDetail"> <id property="id" column="id"></id> <id property="items_id" column="items_id"></id> <id property="items_num" column="items_num"></id> </collection> </resultMap> <select id="findOrderByIdsMap" parameterType="int" resultMap="ordersResultMap2"> select
            o.*,
            u.username,
            u.address,
            od.id,
            od.items_id,
            od.items_num
        from
            orders o,
            user u,
            orderdetail od
        where
            o.user_id = u.id
        and o.id = od.orders_id
        and o.id = #{id} </select> 

第五步:测试

 @Test public void test3(){ /*一对多:模型里有集合*/ //通过session获取代理【jdk实现的代理】 OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 Orders order = orderMapper.findOrderByIdsMap(3); System.out.println(order); System.out.println(order.getUser()); System.out.println(order.getOrdersDetailList()); //sqlSession.commit();//增删改记得提交事务 } 

在这里插入图片描述

2.5 多对多

  • 例如:查询用户信息及用户购买的商品信息,要求将关联信息映射到主pojo的pojo属性中
    在这里插入图片描述
  • 映射思路
  1. 将用户信息映射到user中。
  2. 在user类中添加订单列表属性List<Orders> orderslist,将用户创建的订单映射到orderslist
  3. 在Orders中添加订单明细列表属性List<Orderdetail> detailList,将订单的明细映射到detailList
  4. 在Orderdetail中添加Items属性,将订单明细所对应的商品映射到Items
#查询用户信息及用户购买的商品信息 SELECT u.id, u.username, u.address, o.id, o.number, o.createtime, o.note, od.id detail_id, od.items_id, od.items_num, it.name, it.price, it.detail FROM orders o, USER u, orderdetail od, items it WHERE o.user_id = u.id AND o.id = od.orders_id AND od.items_id = it.id 

第一步:UserMapper接口中添加方法

在这里插入图片描述

第二步:User/Orders/Orderdetail.java

  1. User中添加订单,并提供get/set
    在这里插入图片描述
  2. Orders中还是保持之前添加的订单明细,提供get/set
    在这里插入图片描述
  3. 写一个商品详情类Items,属性与数据库字段对应
    在这里插入图片描述
  • 这里就提供自己需要的属性,并提供get/set、toString
    在这里插入图片描述
  1. 在订单详情(Orderdetail)中添加商品详情(Items),并提供get/set
    在这里插入图片描述

第三步:配置UserMapper.xml

在这里插入图片描述

 <!--查询用户信息及用户购买的商品信息--> <resultMap id="userResultMap2" type="user"> <!--1.匹配user属性--> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="address" property="address"></result> <!--2.匹配user的orderList属性--> <collection property="ordersList" ofType="orders"> <id property="id" column="order_id"></id> <result column="number" property="number"></result> <result column="createtime" property="createtime"></result> <result column="note" property="note"></result> <!--集合里嵌套集合--> <!--3.匹配Orders里的ordersDetail--> <collection property="ordersDetailList" ofType="ordersDetail"> <id property="id" column="detail_id"></id> <result property="items_id" column="items_id"></result> <result property="items_num" column="items_num"></result> <!--4.配置订单详细的商品信息--><!--集合中嵌套association--> <association property="items" javaType="items"> <id property="id" column="items_id"></id> <result property="name" column="name"></result> <result property="price" column="price"></result> <result property="detail" column="detail"></result> </association> </collection> </collection> </resultMap> <select id="findUserAndOrderInfo" resultMap="userResultMap2"> SELECT
            u.id,
            u.username,
            u.address,
            o.id order_id,
            o.number,
            o.createtime,
            o.note,
            od.id detail_id,
            od.items_id,
            od.items_num,
            it.name,
            it.price,
            it.detail
        FROM
            orders o,
            USER u,
            orderdetail od,
            items it
        WHERE
            o.user_id = u.id
        AND o.id = od.orders_id
        AND od.items_id = it.id </select> 

第四步:测试

在这里插入图片描述

 @Test public void test4(){ /*多对多*/ //通过session获取代理【jdk实现的代理】 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 List<User> users = userMapper.findUserAndOrderInfo(); for (User user : users) { System.out.println("用户信息:"+user); for (Orders orders : user.getOrdersList()) { System.out.println("订单信息:"+orders); for (OrdersDetail ordersDetail : orders.getOrdersDetailList()) { System.out.println("订单详情:"+ordersDetail+":"+ordersDetail.getItems()); } System.out.println("---------------------------"); } } //sqlSession.commit();//增删改记得提交事务 } 

第五步:测试单个用户

  1. UserMapper接口中添加方法
    在这里插入图片描述
  2. 修改UserMapper.xml,上面的resultMap复制一份改成userResultMap3即可
    在这里插入图片描述
  3. 测试
    在这里插入图片描述
 @Test public void test5(){ /*多对多*/ //通过session获取代理【jdk实现的代理】 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //System.out.println(userMapper);//返回的是一个代理对象 //查询条件 User user = userMapper.findUserAndOrderInfo1(1); System.out.println("用户信息:"+user); for (Orders orders : user.getOrdersList()) { System.out.println("订单信息:" + orders); for (OrdersDetail ordersDetail : orders.getOrdersDetailList()) { System.out.println("订单详情:" + ordersDetail + ":" + ordersDetail.getItems()); } System.out.println("---------------------------"); } //sqlSession.commit();//增删改记得提交事务 } 

总结

  • resultType:将查询结果按照sql列名与pojo属性名的一致性映射到pojo中。
  • resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
    • association:将关联查询信息映射到一个pojo对象中。
    • collection:将关联查询信息映射到一个list集合中。

第三节 延时加载

  • 延迟加载又叫懒加载,也叫按需加载。也就是说先加载主信息,在需要的时候,再去加载从信息。
  • 在mybatis中,resultMap标签的association标签和collection标签具有延迟加载的功能。

3.1 使用懒加载

第一步:在UserMapper中查看之前写的方法并配置

  • 如果没有就添加上
    在这里插入图片描述
  • 在配置文件中配置
    在这里插入图片描述

第二步:在OrderMapper中写一个方法并配置

在这里插入图片描述

  • 在OrderMapper.xml中配置(通过id查询将数据映射到user中)
    在这里插入图片描述
  • Orders中有user_id属性
    在这里插入图片描述
 <!--懒加载--> <resultMap id="lazyLoadingResultMap" type="orders"> <id column="id" property="id"></id> <id column="note" property="note"></id> <id column="number" property="number"></id> <id column="createtime" property="createtime"></id> <association property="user" select="com.it.mapper.UserMapper.findUserById" column="user_id"></association> </resultMap> <select id="findOrderAndByLazyLoading" resultMap="lazyLoadingResultMap"> SELECT * FROM orders </select> 

第三步:测试(此时还不是懒加载)

  • 注意观察sql语句的执行与执行结果,执行查询Orders后就立即查询用户user,也就是默认的即时加载
    在这里插入图片描述
 @Test public void test6() { /*懒加载*/ OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); List<Orders> list = orderMapper.findOrderAndByLazyLoading(); for (Orders orders : list) { System.out.println("订单信息:"+orders); System.out.println("订单所属用户:"+orders.getUser()); } } 

第四步:在全局配置文件中配置懒加载

在这里插入图片描述

 <!--配置懒加载--> <settings> <setting name="lazyLoadingEnabled" value="true"/> </settings> 
  • 配置完成后再执行一次,对比效果,第一次查询所有的订单,然后再查询id为1用户的订单信息(有2个订单),当使用到id为10的用户的订单信息才去查询加载它(懒加载)
    在这里插入图片描述

本文地址:https://blog.csdn.net/qq_43414199/article/details/108784802

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网