MyBatis框架之第二篇

2019-10-05  本文已影响0人  小小一技术驿站
1、高级参数映射和返回值映射(重点)
        a)Pojo包装pojo的参数映射
        b)当结果集列名与pojo属性名不一致的返回值映射
        2、动态sql(重点)
        3、关联查询结果(重点)
        a)一对一关联结果
        b)一对多关联结果
        4、Mybatis整合spring
        5、逆向工程
        2.事前代码准备
        今天学习内容的练习主要以MyBatis动态代理的方式访问编写访问数据库的代码,因此参照昨天的工程重新创建一个新工程作为今天代码练习的集成,同时需要把一些动态代理需要的目录、空文件提前构建好,以方便后面使用。
        2.1.工程代码结构(UTF8)

        2.2.Mapper映射文件及对应的接口文件
        OrderMapper.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="cn.baidu.dao.OrderMapper">
            <!-- SQL -->
            
        </mapper>
        OrderMapper.java
        package cn.baidu.dao;

        public interface OrderMapper {

        }
        UserMapper.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        <!-- 用户业务映射文件 -->
        <mapper namespace="cn.baidu.dao.UserMapper">
            <!-- SQL -->
            
        </mapper>
        UserMapper.java
        package cn.baidu.dao;

        public interface UserMapper {

        }

        2.3.POJO定义
        1.将昨天工程中的【User.java】拷贝到pojo的包下
        2.把【资料\03.pojo\Order.java】拷贝到pojo的包下。
        2.4.配置文件和属性文件
        1.把昨天工程中Source Folder【config】下的全部配置文件和属性文件拷贝过来。
        2.走查一下配置文件,把没有必要的注释删除,需要修改的配置修改。
        <?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>
            <!-- 配置属性文件 -->
            <properties resource="jdbc.properties" />
            
            <!-- 数据库环境的配置 -->
            <environments default="dev">
                <!-- 开发数据库环境的配置 -->
                <environment id="dev">
                    <!-- 事务管理的配置 -->
                    <transactionManager type="JDBC"/>
                    <!-- 数据源配置:driver, url, username, password -->
                    <dataSource type="POOLED">
                        <property name="driver" value="${jdbc.driver}"/>
                        <property name="url" value="${jdbc.url}"/>
                        <property name="username" value="${jdbc.username}"/>
                        <property name="password" value="${jdbc.password}"/>
                    </dataSource>
                </environment>
            </environments>
            
            <!-- 配置映射文件 -->
            <mappers>
                <!-- 通过包扫描DAO接口的方式批量加载映射文件 -->
                <package name="cn.baidu.dao"/>
            </mappers>
        </configuration>

        2.5.测试类
        package mybatis2;

        import java.io.InputStream;

        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.Before;
        import org.junit.Test;

        public class MyTest {
            
            private SqlSessionFactory sqlSessionFactory;
            
            // 测试初始化函数
            @Before
            public void init() throws Exception {
                // 读取配置文件
                InputStream inputStream = Resources.getResourceAsStream("MyBatisConfig.xml");
                // 根据主配置文件创建会话工厂
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            }

            // 测试通过接口加载与之对应的映射文件
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = null;
                try {
                    sqlSession = sqlSessionFactory.openSession();
                    // 创建DAO的动态代理对象
                    
                    // 执行数据库操作
                    
                } catch(Exception ex) {
                    ex.printStackTrace();
                    throw ex;
                } finally {
                    sqlSession.close();
                }
            }
        }

        3.高级输入映射(重点)
        3.1.综合查询

        综合查询在实际业务需求中十分常见。综合查询页面往往是包含多种查询维度的条件,比如上面的截图就是淘宝的订单查询页面。我们看到查询订单的条件包括:订单基本信息、用户信息、售后信息。
        如果持久层使用MyBatis,应该如何接收参数呢? 
        3.1.1.需求
        查询:用户名是姓王的并且手机是135开头的,订单状态是【待发货】的订单信息。
        【SQL语句】有订单又有用户,SQL应该是一个关联查询:
        SELECT 
            o.orderId,
            o.userId,
            o.orderStatus,
            o.goodsId,
            o.createDateTime
        FROM
            order1 o,
            user u
        WHERE
            u.name LIKE '王%'
            AND u.mobile LIKE '135%'
            AND o.orderStatus = '02'
            AND o.userId = u.userId

        3.1.2.定义综合查询条件用POJO
        因为查询条件是多维度的,它既不属于用户也不属于订单,所以不能用User.java和Order.java,需要重新定义一个包含User和Order的新POJO。
        通常我们把保存查询条件的pojo称为QueryVo.java,其实就是普通的java bean。我们需要订单基本信息和用户信息作为条件进行查询,所以其中包括了用户信息和订单信息。
        【QueryVo.java】
        public class QueryVo {
            // 用户信息
            private User user;
            
            // 订单信息
            private Order order;

            setter/getter。。。。。
        }
        上面需求中的SQL需要两方面条件,一方面是订单的,一方面是用户的,所以可以在QueryVo中定义一个Order对象用于保存订单的查询条件,再定义一个User对象用于保存用户的查询条件。这样不容易混乱也不容易出现名称相似的属性造成的不知道该用哪个。
        注意:我们不要把user的属性和order的属性条件混合到一起定义,这样定义没有错,而且在参数映射时也简单了,但是会让Vo变得很混乱,分不清属性谁是谁的。
        3.1.3.SQL映射文件
        【OrderMapper.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="cn.baidu.dao.OrderMapper">
            <!-- SQL -->
            <!-- 根据QueryVo查询订单信息 -->
            <select id="findOrderByQueryVo" parameterType="cn.baidu.pojo.QueryVo"
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    o.orderId,
                    o.userId,
                    o.orderStatus,
                    o.goodsId,
                    o.createDateTime
                FROM
                    order1 o,
                    user u
                WHERE
                    u.name LIKE #{user.name}
                    AND u.mobile LIKE #{user.mobile}
                    AND o.orderStatus = #{order.orderStatus}
                    AND o.userId = u.userId
            </select>
        </mapper>

        3.1.4.定义接口
        【OrderMapper.java】
        package cn.baidu.dao;

        import cn.baidu.pojo.QueryVo;
        import cn.baidu.pojo.Order;

        public interface OrderMapper {
            
            // 根据综合查询条件查询订单信息
            public Order findOrderByQueryVo(QueryVo vo) throws Exception;
        }

        3.1.5.客户端测试程序
        【MyTest.java】
            // 测试根据QueryVo查询订单信息
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                User user = new User();
                Order order = new Order();
                user.setName("王%");
                user.setMobile("135%");
                order.setOrderStatus("02");
                QueryVo vo = new QueryVo();
                vo.setOrder(order);
                vo.setUser(user);
                // 执行数据库操作
                List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
                System.out.println(orderList);
                sqlSession.close();
            }
        <SQL映射规范>(需要掌握)
        ·参数映射规范(四)
            传多个参数并且是POJO包装类型时,parameterType="pojo包装pojo类型",占位符中的变量名等于Vo的属性.属性.属性...,直到找到传参属性名为止。

        4.高级输出映射(重点)
        按照返回值映射的规范MyBatis可以将SQL结果集自动的生成指定类型的java对象,但是如果满足不了返回值映射的规范怎么办?简单点说就是结果集列名与pojo中的属性名不相等的时候我们怎么做返回值映射?
        解决的办法:就是手动定义返回值映射。
        4.1.需求
        根据订单id查询数据库中order2表的订单信息。但order2表的最大问题就是字段名是以下划线分割的,这与Order的pojo中的属性名不一致。
        4.2.手动定义返回值映射
        4.2.1.定义返回值映射
        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <resultMap> 用于自定义返回值映射的规则,即自定义哪个列名对应哪个属性名。
        id  返回值映射的唯一标识
        type    返回值映射中java对象的类型
        <result>    用于定义一个返回值映射规范的标签,一个<resultMap>可以包含多个<result>
        column  返回值映射中的列名
        property    返回值映射中的属性名
        <id>    用于定义返回值映射中主键列名与字段名的映射关系。用法和<result>一模一样,只是增加可读性。
        <SQL映射示例>
            <!-- 自定义返回值映射的规范 -->
            <resultMap type="cn.baidu.pojo.Order" id="order2ResultMap">
                <id column="order_id" property="orderId"/>
                <!-- <result column="order_id" property="orderId"/> -->
                <result column="user_id" property="userId"/>
                <result column="order_status" property="orderStatus"/>
                <result column="goods_id" property="goodsId"/>
                <result column="create_date_time" property="createDateTime"/>
            </resultMap>
        自定义了规范,MyBatis就可以利用这个自定义规范进行返回值映射了。
        4.2.2.SQL
        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        resultMap   引用返回值映射的自定义规范
        <SQL映射示例>
            <!-- 根据id查询order2表的订单信息 -->
            <select id="findOrder2ById" parameterType="String" resultMap="order2ResultMap">
                SELECT 
                    order_id,
                    user_id,
                    order_status,
                    goods_id,
                    create_date_time
                FROM
                    order2
                WHERE
                    order_id = #{orderId}
            </select>

        4.2.3.接口
        【OrderMapper.java】
            // 根据id查询订单信息
            public Order findOrder2ById(String orderId) throws Exception;

        4.2.4.客户端测试程序
        【MyTest.java】
            // 测试根据id查询订单信息
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                // 执行数据库操作
                Order orderInfo = orderMapper.findOrder2ById("6d081184-433e-11e7-ab09-448a5b6dba5c");
                System.out.println(orderInfo); 
                sqlSession.close();
            }

        4.3.用SQL字段别名满足返回值映射规范
        利用SQL的字段可以定义别名的功能,满足字段名与POJO属性名相同的要求。
        4.3.1.SQL
        【OrderMapper.xml】
            <!-- 根据id查询order2表的订单信息2 -->
            <select id="findOrder2ById2" parameterType="String" resultType="cn.baidu.pojo.Order">
                SELECT 
                    order_id as orderId,
                    user_id as userId,
                    order_status as orderStatus,
                    goods_id as goodsId,
                    create_date_time as createDateTime
                FROM
                    order2
                WHERE
                    order_id = #{orderId}
            </select>

        4.3.2.接口
        【OrderMapper.java】
            // 根据id查询订单信息2
            public Order findOrder2ById2(String orderId) throws Exception;

        4.3.3.客户端测试程序
        【MyTest.java】
            // 测试根据id查询订单信息
            @Test
            public void test2() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                // 执行数据库操作
        //      Order orderInfo = orderMapper.findOrderById("6d081184-433e-11e7-ab09-448a5b6dba5c");
                Order orderInfo = orderMapper.findOrder2ById2("6d081184-433e-11e7-ab09-448a5b6dba5c");
                System.out.println(orderInfo);
                sqlSession.close();
            }

        5.动态SQL(重点)
        本章内容针对SQL映射,赋予SQL映射更加强大灵活的特性,让SQL映射更能适应复杂多变的参数请求。因此本节内容比较杂,内容也较多,但每块内容都相对独立,不难掌握。
        5.1.1.动态SQL条件

        5.1.2.<if>标签
        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <if>    用于判断它包含的SQL语句是否需要添加。
        test    判断的逻辑条件,and表示与,or表示或,逻辑判断为true是添加包含的SQL语句,false就忽略。
        <SQL映射示例>
            <!-- 根据动态条件查询订单信息 -->
            <select id="findOrderByQueryVo2" parameterType="cn.baidu.pojo.QueryVo" 
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    o.orderId,
                    o.userId,
                    o.orderStatus,
                    o.goodsId,
                    o.createDateTime
                FROM
                    order1 o,
                    user u
                WHERE 1 = 1
                    <if test="user.name != null and user.name != ''">
                        AND u.name LIKE #{user.name}
                    </if>
                    <if test="user.mobile != null and user.mobile != ''">
                        AND u.mobile LIKE #{user.mobile}
                    </if>
                    <if test="order.orderStatus != null and order.orderStatus != ''">
                        AND o.orderStatus = #{order.orderStatus}
                    </if>
                    and o.userId = u.userId
            </select>

        【OrderMapper.java】
            // 根据动态查询条件查询订单信息
            public List<Order> findOrderByQueryVo2(CustomQueryVo vo) throws Exception;

        【MyTest.java】
            // 测试根据动态查询条件查询订单信息
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                User user = new User();
                Order order = new Order();
                user.setName("王%");
                user.setMobile("135%");
                order.setOrderStatus("02");
                QueryVo vo = new QueryVo();
                vo.setOrder(order);
                vo.setUser(user);
                // 执行数据库操作
        //      List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
                List<Order> orderList = orderMapper.findOrderByQueryVo2(vo);
                System.out.println(orderList);
                sqlSession.close();
            }

        if标签不仅仅用于动态条件,SQL中所有接收参数的部分都可以通过if判断决定是否要追加,比如udate更新中可以实现更新项目的动态更新:
            <update id="updateUser" parameterType="cn.baidu.pojo.User">
                UPDATE user 
                SET
                    <if test="name != null and name != ''">
                        name = #{name}, 
                    </if>
                    <if test="mobile != null and mobile != ''">
                        mobile = #{mobile}, 
                    </if>
                    <if test="sex != null and sex != ''">
                        sex = #{sex}, 
                    </if>
                    <if test="age != null and age != ''">
                        age = #{age}, 
                    </if>
                    <if test="address != null and address != ''">
                        address = #{address},
                    </if>
                WHERE
                    userId = #{userId}
            </update>
        上面的示例是有缺陷的,这个等到后面的学习中会改进它,现在只是让大家看到if标签不仅仅应用于where条件。
        5.2.完善动态SQL条件
        5.2.1.<where>标签
        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <where> 用于构建完整where条件的标签,有了它就不需要写where关键字了
        它还能够去掉第一个条件前面的and或or,因此<where>可以和<if>标签组合实现更完美的动态条件。
        <SQL映射示例>
            <!-- 根据动态条件查询订单信息(改进) -->
            <select id="findOrderByQueryVo3" parameterType="cn.baidu.pojo.QueryVo" 
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    o.orderId,
                    o.userId,
                    o.orderStatus,
                    o.goodsId,
                    o.createDateTime
                FROM
                    order1 o,
                    user u
                <where>
                    <if test="user.name != null and user.name != ''">
                        AND u.name LIKE #{user.name}
                    </if>
                    <if test="user.mobile != null and user.mobile != ''">
                        AND u.mobile LIKE #{user.mobile}
                    </if>
                    <if test="order.orderStatus != null and order.orderStatus != ''">
                        AND o.orderStatus = #{order.orderStatus}
                    </if>
                    and o.userId = u.userId
                </where>
            </select>
        【OrderMapper.java】
            // 根据动态查询条件查询订单信息(改进)
            public List<Order> findOrderByQueryVo3(CustomQueryVo vo) throws Exception;
        【MyTest.java】
            // 测试根据动态查询条件查询订单信息
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                User user = new User();
                Order order = new Order();
                user.setName("王%");
                user.setMobile("135%");
                order.setOrderStatus("02");
                QueryVo vo = new QueryVo();
                vo.setOrder(order);
                vo.setUser(user);
                // 执行数据库操作
        //      List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
        //      List<Order> orderList = orderMapper.findOrderByQueryVo2(vo); 
                List<Order> orderList = orderMapper.findOrderByQueryVo3(vo);
                System.out.println(orderList);
                sqlSession.close();
            }

        5.3.SQL代码片段的复用
        5.3.1.定义可重用的SQL代码段
        【OrderMapper.xml】把【findOrderByQueryVo2】和【findOrderByQueryVo3】中的条件提取出去:
        <说明>(需要掌握)
        项目  解释
        <sql>   定义可共用SQL片段的标签。将可共用的SQL片段(可以包含其他动态标签)包含在<sql></sql>中间
        id  这个共用SQL片段的唯一标识
        <SQL映射示例>
            <!-- 订单信息的查询条件 -->
            <sql id="order_query_condition">
                <if test="user.name != null and user.name != ''">
                    AND u.name LIKE #{user.name}
                </if>
                <if test="user.mobile != null and user.mobile != ''">
                    AND u.mobile LIKE #{user.mobile}
                </if>
                <if test="order.orderStatus != null and order.orderStatus != ''">
                    AND o.orderStatus = #{order.orderStatus}
                </if>
            </sql>

        修改后的【findOrderByQueryVo2】和【findOrderByQueryVo3】
        <说明>(需要掌握)
        项目  解释
        <include>   引用已经定义好的SQL片段
        refid   引用的SQL片段的id
        <SQL映射示例>
            <!-- 根据动态条件查询订单信息 -->
            <select id="findOrderByQueryVo2" parameterType="cn.baidu.pojo.QueryVo" 
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    o.orderId,
                    o.userId,
                    o.orderStatus,
                    o.goodsId,
                    o.createDateTime
                FROM
                    order1 o,
                    user u
                WHERE 1 = 1
                    <include refid="order_query_conditions"/>
                    and o.userId = u.userId
            </select>
            
            <!-- 根据动态条件查询订单信息(改进) -->
            <select id="findOrderByQueryVo3" parameterType="cn.baidu.pojo.QueryVo" 
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    o.orderId,
                    o.userId,
                    o.orderStatus,
                    o.goodsId,
                    o.createDateTime
                FROM
                    order1 o,
                    user u
                <where>
                    <include refid="order_query_conditions"/>
                    and o.userId = u.userId
                </where>
            </select>
        可以测试一下,结果仍然可以执行。
        5.4.动态多值SQL条件:foreach

        上面的屏幕尺寸是可以多选的。对于同一个条件可以选择多个条件值的情况下如何处理?
        5.4.1.处理in条件
        比如根据多个订单状态查询订单信息,我们需要传递多个订单状态。我们可以在查询条件的pojo类QueryVo中添加一个List<String>类型的属性,也可以直接传递List<String>类型的java对象。
        1.在QueryVo中定义List<String>类型的属性:
        【QueryVo.java】
        public class QueryVo {
            。。。。。。。
            // 订单状态列表
            private List<String> orderStatusList;
            。。。。。。。

            /**
             * @return the orderStatusList
             */
            public List<String> getOrderStatusList() {
                return orderStatusList;
            }

            /**
             * @param orderStatusList the orderStatusList to set
             */
            public void setOrderStatusList(List<String> orderStatusList) {
                this.orderStatusList = orderStatusList;
            }
        }

        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <foreach>   在参数映射中,用于循环遍历集合类型的参数。
        collection  表示要循环遍历的集合对象名称
        item    每次遍历时使用的临时变量名称,在循环内部用占位符来引用
        separator   每次循环之间的分隔符号
        open    循环开始之前的SQL语句部分(可选)
        close   循环结束之后的SQL语句部分(可选)
        <SQL映射示例>
            <!-- 根据多个订单状态查询订单信息(Vo中包装List) -->
            <select id="findOrderByOrderStatus" parameterType="cn.baidu.pojo.QueryVo"
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    orderId,userId,orderStatus,goodsId,createDateTime
                FROM
                    order1
                WHERE
                    <!-- 不带open和close属性的形式 -->
                    orderStatus in (
                    <foreach collection="orderStatusList" item="orderStatus" separator=",">
                        #{orderStatus}
                    </foreach>
                    )
                    或者
                    <foreach collection="orderStatusList" item="orderStatus" separator=","
                        open="orderStatus in (" close=")">
                        #{orderStatus}
                    </foreach>
            </select>
        <SQL映射规范>(需要掌握)
        ·参数映射规范(五)——<foreach>标签专用
            处理集合参数,如果参数是parameterType="Pojo(包含List属性)"时, <foreach>中collection必须是List属性的变量名称。

        【OrderMapper.java】
            // 根据多个订单状态查询订单信息(Vo包装List)
            public List<Order> findOrderByOrderStatus(CustomQueryVo vo) throws Exception;

        【MyTest.java】
            // 根据多个订单状态查询订单信息(Vo包装List)
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = null; 
                sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                List<String> orderStatusList = new ArrayList<String>();
                orderStatusList.add("01");
                orderStatusList.add("02");
                orderStatusList.add("03");
                QueryVo vo = new QueryVo();
                vo.setOrderStatusList(orderStatusList);
                // 执行数据库操作
                List<Order> orderList = orderMapper.findOrderByOrderStatus(vo);
                System.out.println(orderList); 
                sqlSession.close();
            }

        2.直接传递List:
        【OrderMapper.xml】
            <!-- 根据多个订单状态查询订单信息2(直接传递List) -->
            <select id="findOrderByOrderStatus2" parameterType="java.util.List"
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    orderId,userId,orderStatus,goodsId,createDateTime
                FROM
                    order1
                WHERE
                    <foreach collection="list" item="orderStatus" separator=","
                        open="orderStatus in (" close=")">
                        #{orderStatus}
                    </foreach>
            </select>
        <SQL映射规范>(需要掌握)
        ·参数映射规范(六)——<foreach>标签专用
            处理集合参数,如果参数是parameterType="List"时,<foreach>中collection属性值必须是list(必须小写,不能变)

        【OrderMapper.java】
            // 根据多个订单状态查询订单信息2(直接传递List)
            public List<Order> findOrderByOrderStatus2(List<String> statusList) throws Exception;

        【MyTest.java】
            // 根据多个订单状态查询订单信息1(Vo包装List)
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = null; 
                sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                List<String> orderStatusList = new ArrayList<String>();
                orderStatusLis.add("01");
                orderStatusLis.add("02");
                orderStatusLis.add("03");
                CustomQueryVo vo = new CustomQueryVo();
                vo.setOrderStatusList(orderStatusLis);
                // 执行数据库操作
        //      List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
                List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis);
                System.out.println(orderList2); 
                sqlSession.close();
            }
        5.4.2.or条件
        【OrderMapper.xml】
            <!-- 根据多个订单状态查询订单信息3(or条件) -->
            <select id="findOrderByOrderStatus3" parameterType="java.util.List"
                resultType="cn.baidu.pojo.Order">
                SELECT 
                    orderId,userId,orderStatus,goodsId,createDateTime
                FROM
                    order1
                WHERE
                    <foreach collection="list" item="orderStatus" separator="or">
                        orderStatus = #{orderStatus}
                    </foreach>
            </select>

        【OrderMapper.java】
            // 根据多个订单状态查询订单信息3(or条件)
            public List<Order> findOrderByOrderStatus3(List<String> statusList) throws Exception;

        【MyTest.java】
            // 根据多个订单状态查询订单信息
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = null; 
                sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                List<String> orderStatusList = new ArrayList<String>();
                orderStatusLis.add("01");
                orderStatusLis.add("02");
                orderStatusLis.add("03");
                CustomQueryVo vo = new CustomQueryVo();
                vo.setOrderStatusList(orderStatusLis);
                // 执行数据库操作
        //      List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
        //      List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis); 
                List<Order> orderList3 = orderMapper.findOrderByOrderStatus3(orderStatusLis);
                System.out.println(orderList3); 
                sqlSession.close();
            }

        5.5.小结
        上面的动态标签: <if>, <where>, <sql>, <foreach>无论你如何使用我们始终要记住一个宗旨:
            保证动态形成的SQL语句的语法正确
        只要你能包装SQL语法正确, 你就可以灵活的使用这些动态标签实现你自己的动态SQL。
        6.关联查询结果(重点)
        6.1.商品订单数据模型


        注意:这里面两个表的关联都是由SQL控制的,跟MyBatis一点关系都没有,现在我们面临的问题就是怎样把具有关联关系的结果集通过结果集映射返回给Java程序。
        6.2.一对一查询结果集
        6.2.1.SQL语句
                SELECT  
                    o.orderId,
                    o.goodsId,
                    o.orderStatus,
                    u.name,
                    u.address,
                    u.mobile
                FROM
                    order1 o,
                    user u
                WHERE
                    o.userId = u.userId
                    AND o.orderId = '52076fa9-433e-11e7-ab09-448a5b6dba5c'

        6.2.2.修改订单POJO
        如果查询结果中包含用户信息,就需要在Order.java pojo中增加User类型的属性,然后把用户信息保存在这个User属性中。
        package cn.baidu.pojo;

        /**
         * 订单信息POJO
         * 
         * @author Derek Sun
         *
         */
        public class Order { 
            
            private String orderId;

            private Integer userId;

            private String orderStatus;

            private String goodsId;

            private Date createDateTime;
            
            private User user;

             。。。。。。
        }
        在实际业务中可能不仅仅包含用户信息,还可能有订单对应的商品信息、物流信息等等。
            由于查询结果中需要包含一个User类型的对象,这样的结果集结构比较复杂,因此需要我们手动定义返回值映射,这就需要ResultMap发挥作用的时候了。
        需要在定义返回值映射时在ResultMap中定义一个User类型的对象,并把属于用户的查询结果映射给User对象的属性。
        6.2.3.ResultMap中定义POJO对象
        【OrderMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <association>   用于在ResultMap标签中定义POJO对象 
        property    定义的POJO对象名称(注意:名称不能随便命名,必须符合返回值映射规范)
        javaType    定义的POJO对象的类型
        <SQL映射示例>
            <!-- 一对一查询结果集的返回 -->
            <!-- 定义订单综合查询结果与自定义订单pojo属性之间的对应关系 -->
            <resultMap type="cn.baidu.pojo.Order" id="orderResultMap1">
                <id column="order_id" property="orderId" />
                <result column="goods_id" property="goodsId" />
                <result column="order_status" property="orderStatus" />
                <association property="user" javaType="cn.baidu.pojo.User">
                    <result column="name" property="name"/>
                    <result column="address" property="address"/>
                    <result column="mobile" property="mobile"/>
                </association>
            </resultMap>
            <!-- 根据订单id查询订单综合信息(订单基本信息、所属用户信息...) -->
            <select id="findOrderAndUserByOrderId" parameterType="string" 
                resultMap="orderResultMap1"> 
                SELECT  
                    o.orderId,
                    o.goodsId,
                    o.orderStatus,
                    u.name,
                    u.address,
                    u.mobile
                FROM
                    order1 o,
                    user u
                WHERE
                    o.userId = u.userId
                    AND o.orderId = #{id}
            </select>
        <SQL映射规范>(需要掌握)
        ·返回值映射规范(四)
            在<resultMap>中用<association>定义POJO对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对一结果的映射)

        6.2.4.定义接口
        【OrderMapper.java】
            // 根据订单id查询订单综合信息(订单基本信息、所属用户信息...)
            public Order findOrderAndUserByOrderId(String orderId) throws Exception;
        6.2.5.客户端测试程序
        【MyTest.java】
            // 测试根据订单id查询订单综合信息(订单基本信息、所属用户信息...)
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                Order order = orderMapper.findOrderAndUserByOrderId("5f560c1e-433e-11e7-ab09-448a5b6dba5c");
                System.out.println(order);
                sqlSession.close();
            }

        6.2.6.扩展
        如果返回多条一对一的查询结果,该如何来做?
        1.SQL
        SELECT
            o.orderId,
            o.orderStatus,
            o.goodsId,
            u.userId,
            u.name,
            u.address
        FROM
            order1 o,
            user u
        WHERE
            o.userId = u.userId
            AND o.orderStatus = '02'

        2.POJO
        同【Order.java】
        3.接口定义
            // 根据订单状态查询订单综合信息(订单基本信息、所属用户信息...)
            public List<Order> selectOrderAndUserByOrderStatus(String orderStatus) throws Exception;

        4.映射文件
            <!-- 根据订单状态查询订单综合信息(订单基本信息、所属用户信息...) -->
            <select id="selectOrderAndUserByOrderStatus" parameterType="String" 
                resultMap="customOrderResultType">
                SELECT
                    o.orderId,
                    o.orderStatus,
                    o.goodsId,
                    u.userId,
                    u.name,
                    u.address
                FROM
                    order1 o,
                    user u
                WHERE
                    o.userId = u.userId
                    AND o.orderStatus = #{status}
            </select>

        5.客户端测试
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); 
                List<CustomOrder> orderList = orderMapper.selectOrderAndUserByOrderStatus("02");
                System.out.println(orderList);
                sqlSession.close();
            }
        执行结果:

        总结:无论是单条还是多条一对一结果,<resultMap> + <association>的组合都适用。association里面还可以再嵌套association。

        6.3.一对多查询结果集
        6.3.1.SQL语句
                SELECT 
                    u.name,
                    u.address, 
                    u.mobile,
                    o.order_id,
                    o.order_status,
                    o.goods_id
                FROM
                    user u,
                    order2 o
                WHERE
                    o.user_id = u.userId
                    AND u.userId = 1001 
        从SQL查询的结果集上看用户名和地址都是重复的,这个用户相关的订单信息是多条不同的,这样的结果集最终返回到java对象中应该是一个用户信息,其中包含一个关于这个用户的订单信息的List集合。
        6.3.2.修改用户POJO
        如果查询用户结果中包含多个订单信息,就需要在User.java pojo中增加Order类型的List属性,然后把属于这个用户多条订单信息保存到List<Order>属性中。
        package cn.baidu.pojo;

        import java.util.List;

        /**
         * 用户信息POJO
         * 
         * @author Derek Sun
         *
         */
        public class User { 
            
            private String name;

            private int userId;
            
            private String mobile;
            
            private String sex;
            
            private int age;
            
            private String address;

            // 用户订单信息列表
            private List<Order> orderList;

             。。。。。。。
        }

        在实际业务中可能不仅仅包含订单信息,还可能有用户信用度信息、用户消费额度信息、推荐商品信息列表等等。

        由于查询结果中需要包含一个List<Order>类型的对象,这样的结果集结构比较复杂,因此需要我们手动定义返回值映射,这就需要ResultMap发挥作用的时候了。
        需要在定义返回值映射时在ResultMap中定义一个List<Order>类型的对象,并把属于这个用户的订单查询结果映射给List<Order>对象。
        6.3.3.ResultMap中定义List对象
        【UserMapper.xml】
        <说明>(需要掌握)
        项目  解释
        <collection>    用于在ResultMap标签中定义List类型的对象 
        property    定义的List类型的对象名称(注意:名称不能随便命名,必须符合返回值映射规范)
        ofType  List中泛型的类型,即List其中一个对象的类型
        <SQL映射示例>
            <!-- 一对多查询结果集返回 -->
            <!-- 定义用户综合查询结果集与自定义用户pojo属性之间的对应关系 -->
            <resultMap type="cn.baidu.pojo.User" id="userResultMap">
                <result column="name" property="name" />
                <result column="address" property="address" /> 
                <result column="mobile" property="mobile"/>
                <collection property="orderList" ofType="cn.baidu.pojo.Order">
                    <id column="order_id" property="orderId" />
                    <result column="order_status" property="orderStatus" />
                    <result column="goods_id" property="goodsId" />
                </collection>
            </resultMap>
            <!-- 根据用户id查询用户综合信息(用户基本信息, 用户订单信息....) -->
            <select id="findUserAndOrderByUserId" parameterType="int" resultMap="userResultMap">
                SELECT 
                    u.name,
                    u.address, 
                    u.mobile,
                    o.order_id,
                    o.order_status,
                    o.goods_id
                FROM
                    user u,
                    order2 o
                WHERE
                    o.user_id = u.userId
                    AND u.userId = #{id}
            </select>
        <SQL映射规范>(需要掌握)
        ·返回值映射规范(五)
            在<resultMap>中用<collection>定义List对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对多结果的映射)

        6.3.4.定义接口
        【OrderMapper.java】
        package cn.baidu.dao;
        import cn.baidu.pojo.User;
        public interface UserMapper {
            // 根据用户id查询用户综合信息(用户基本信息, 用户订单信息....)
            public User findUserAndOrderByUserId(Integer id) throws Exception;
        }
        6.3.5.客户端测试程序
        【MyTest.java】
            // 测试根据用户id查询用户综合信息(用户基本信息, 用户订单信息....)
            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                User user = userMapper.findUserAndOrderByUserId(1001);
                sqlSession.close();
            }

        6.3.6.扩展
        如果返回多条一对多的查询结果,该如何来做?(多条一对多也可以理解成多对多,实际上多对多最终都是转化成一对多来实现的。)
        1.SQL
        SELECT
            u.userId,
            u.name,
            u.mobile,
            o.orderId,
            o.orderStatus,
            o.goodsId
        FROM
            user u,
            order1 o
        WHERE
            u.userId = o.userId
            AND u.name LIKE '王%'

        2.POJO
        同【User.java】

        3.接口定义
            // 根据用户名模糊查询用户综合信息(用户基本信息, 用户订单信息....)
            public List<User> selectUserAndOrderListByUserName(String userName) throws Exception;

        4.映射文件
            <!-- 根据用户名模糊查询用户综合信息(用户基本信息, 用户订单信息....) -->
            <select id="selectUserAndOrderListByUserName" parameterType="String"
                resultMap="userResultMap">
                SELECT
                    u.userId,
                    u.name,
                    u.mobile,
                    o.orderId,
                    o.orderStatus,
                    o.goodsId
                FROM
                    user u,
                    order1 o
                WHERE
                    u.userId = o.userId
                    AND u.name LIKE #{userName}
            </select>

        5.客户端测试

            @Test
            public void test1() throws Exception {
                SqlSession sqlSession = sqlSessionFactory.openSession();
                // 创建DAO的动态代理对象
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                List<User> userList = userMapper.selectUserAndOrderListByUserName("王%");
                sqlSession.close();
            }
        执行结果:

        总结:无论是单条还是多条一对多结果,<resultMap> + <collection>的组合都适用。collection里面还可以再嵌套collection,但是一般没有那么复杂的数据结构。
        7.输入输出映射小结(重点)
        <SQL映射规范>(需要掌握)
        ·参数映射规范
            1)传单个参数时,parameterType="java简单类型",占位符中的变量可以任意名称,但不能没有。
            2)传单个参数时,parameterType="java简单类型",拼接符中的变量名必须是value,也不能没有。
            3)传多个参数时,parameterType="pojo类型",占位符或拼接符的变量名必须等于pojo中的属性名。
            4)传多个参数并且是POJO包装类型时,parameterType="pojo包装pojo类型",占位符中的变量名等于Vo的属性.属性.属性...,直到找到传参属性为止。
            5)<foreach>标签专用——处理集合参数,如果参数是parameterType="Pojo(包含List属性)"时, <foreach>中collection必须是List属性的变量名称。
            6)<foreach>标签专用——处理集合参数,如果参数是parameterType="List"时,<foreach>中collection属性值必须是list(必须小写,不能变)。

        ·返回值映射规范
            1)返回单值时,resultType="java简单类型",值直接返回给java程序。
            2)返回单条记录时,resultType="pojo类型",结果集的列名必须等于pojo的属性名。
            3)返回多条记录时,resultType="集合的pojo泛型的类型",结果集列名必须等于pojo泛型的属性名。
            4)在<resultMap>中用<association>定义POJO对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对一结果的映射)
            5)在<resultMap>中用<collection>定义List对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对多结果的映射)
上一篇下一篇

猜你喜欢

热点阅读