MyBatis框架的学习(四)

前面对MyBatis框架的学习中,我们对Mapper.xml映射文件多少有些了解。本文将对Mapper.xml映射文件作更加细致的梳理,首先从Mapper.xml文件中的输入和输出映射开始。本文案例代码的编写是建立在前文MyBatis框架的学习(三)案例基础之上的!

输入映射和输出映射

Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

parameterType(输入类型)

传递简单类型

传递简单类型,我之前已讲过,这里只给出案例,如下:
这里写图片描述

传递pojo对象

MyBatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。传递pojo对象之前也已讲过,这里同样只给出案例,如下:
这里写图片描述

传递pojo包装对象

开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。即pojo类中包含pojo类。
例如这样一个需求:根据用户id查询用户信息,查询条件放到QueryVo类的user属性中。有需求,就要解决它。我们可在cn.itheima.mybatis.po包下新建一个QueryVo类,如下:

public class QueryVo {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

}
 

    接下来我们就要在UserMapper.xml映射文件中编写sql语句了,即在UserMapper.xml映射文件中添加如下配置信息:

    <select id="getUserByQueryVo" parameterType="queryvo" resultType="user">
        select * from user where id=#{user.id};
    </select>
     

      使用包装类型查询用户时,可使用ognl从对象中取属性值,并且如果是包装对象可以使用.操作符来取内容的属性。
      然后在UserMapper接口中添加如下方法:

      User getUserByQueryVo(QueryVo queryVo);
       
      • 1

      最后在UserMapperTest单元测试类编写如下测试方法:

      @Test
      public void testGetUserByQueryVo() {
          SqlSession sqlSession = sqlSessionFactory.openSession();
          // 获得mapper代理对象
          UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
          // 创建一个QueryVo对象
          QueryVo queryVo = new QueryVo();
          User user = new User();
          user.setId(10);
          queryVo.setUser(user);
          // 执行查询
          User result = userMapper.getUserByQueryVo(queryVo);
          System.out.println(result);
          sqlSession.close();
      }
       

        传递HashMap

        传递HashMap在实际开发中用的很少,但我还是要讲一下。以例明示——传递HashMap综合查询用户信息,在UserMapper.xml映射文件中添加如下配置信息:

        <!-- 传递HashMap综合查询用户信息 -->
        <select id="findUserByHashmap" parameterType="hashmap" resultType="user">
           select * from user where id=#{id} and username like '%${username}%'
        </select>
         

          上面的id和username是HashMap的key。
          接着在UserMapper接口中添加如下方法:

          User findUserByHashmap(HashMap<String, Object> map);
           
          • 1

          最后在UserMapperTest单元测试类编写如下测试方法:

          @Test
          public void testFindUserByHashmap() {
              SqlSession sqlSession = sqlSessionFactory.openSession();
              // 获得mapper代理对象
              UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
              // 构造查询条件Hashmap对象
              HashMap<String, Object> map = new HashMap<String, Object>();
              map.put("id", 30);
              map.put("username", "赵云");
              // 执行查询
              User result = userMapper.findUserByHashmap(map);
              System.out.println(result);
              sqlSession.close();
          }
           

            resultType(输出类型)

            输出简单类型

            有这样一个需求:查询用户表中的记录数。有需求就要解决它,我们首先在UserMapper.xml映射文件中添加如下配置信息:

            <!-- 查询用户表中的记录数 -->
            <select id="getUserCount" resultType="int">
                SELECT COUNT(*) FROM `user`
            </select>
             

              接着在UserMapper接口中添加如下方法:

              Integer getUserCount();
               
              • 1

              最后在UserMapperTest单元测试类编写如下测试方法:

              @Test
              public void testGetUserCount() {
                  SqlSession sqlSession = sqlSessionFactory.openSession();
                  // 获得mapper代理对象
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                  // 执行查询
                  int count = userMapper.getUserCount();
                  System.out.println(count);
                  sqlSession.close();
              }
               

                输出简单类型必须查询出来的结果集只有一条记录,最终将第一个字段的值转换为输出类型。

                输出pojo对象

                输出pojo对象,我之前已讲过,这里只给出案例,如下:
                这里写图片描述

                输出pojo列表

                输出pojo列表,我之前同样已讲过,这里只给出案例,如下:
                这里写图片描述
                这儿再给出一个案例——查询订单的所有信息。我们mybatis数据库中已经有了订单表(orders表)了,如下:
                这里写图片描述
                大家可能想到不会想,就会像下面这样做。首先在cn.itheima.mybatis.po包下新建一个Orders类:

                public class Orders {
                    private Integer id;
                
                    private Integer userId;
                
                    private String number;
                
                    private Date createtime;
                
                    private String note;
                
                    public Integer getId() {
                        return id;
                    }
                
                    public void setId(Integer id) {
                        this.id = id;
                    }
                
                    public Integer getUserId() {
                        return userId;
                    }
                
                    public void setUserId(Integer userId) {
                        this.userId = userId;
                    }
                
                    public String getNumber() {
                        return number;
                    }
                
                    public void setNumber(String number) {
                        this.number = number == null ? null : number.trim();
                    }
                
                    public Date getCreatetime() {
                        return createtime;
                    }
                
                    public void setCreatetime(Date createtime) {
                        this.createtime = createtime;
                    }
                
                    public String getNote() {
                        return note;
                    }
                
                    public void setNote(String note) {
                        this.note = note == null ? null : note.trim();
                    }
                
                }
                 

                  然后在cn.itheima.mybatis.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.itheima.mybatis.mapper.OrderMapper">
                      <select id="getOrderList" resultType="orders">
                          select * from orders;
                      </select>
                  </mapper>
                   

                    紧接着在cn.itheima.mybatis.mapper包下创建一个OrderMapper接口:

                    public interface OrderMapper {
                        List<Orders> getOrderList();
                    }
                     

                      最后创建OrderMapper接口的单元测试类——OrderMapperTest.java,修改OrderMapperTest类的内容为:

                      public class OrderMapperTest {
                      
                          private SqlSessionFactory sqlSessionFactory = null; // 工厂对象一般在我们的系统中是单例的
                      
                          @Before
                          public void init() throws IOException {
                              // 第一步,创建SqlSessionFactoryBuilder对象
                              SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
                              // 第二步,加载配置文件
                              InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
                              // 第三步,创建SqlSessionFactory对象
                              sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
                          }
                      
                          @Test
                          public void testGetOrderList() {
                              SqlSession sqlSession = sqlSessionFactory.openSession();
                              OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                              List<Orders> orderList = orderMapper.getOrderList();
                              for (Orders orders : orderList) {
                                  System.out.println(orders);
                              }
                              sqlSession.close();
                          }
                      
                      }
                       

                        在testGetOrderList方法中的以下代码处打一个断点:

                        for (Orders orders : orderList) {
                         
                        • 1

                        然后以Debug模式运行该方法,可发现查询出来的每一个Orders对象中的userId属性值都为null,如下:
                        这里写图片描述
                        很明显这并不是我们所想要的结果。为了达到我们预期的效果,可为user_id列加别名,即将OrderMapper.xml映射文件中id为getOrderList的select元素修改为:

                        <select id="getOrderList" resultType="orders">
                            select id,user_id userId,number,createtime,note from orders;
                        </select>
                         

                          只要你返回的结果的列名和pojo中的属性一致,就可以自动映射了。
                          这样当我们再次以Debug模式运行testGetOrderList方法,就能达到我们预期的结果了,如下:
                          这里写图片描述
                          这种方式比较简单粗暴,其实要达到我们所预期的效果,还有另一种方式,那就是使用resultMap这个属性,下面我就会讲到。

                          resultMap

                          resultMap可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
                          resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
                          现在我就来实现查询订单所有信息的需求,而不是像上面那样简单粗暴地给user_id列加别名。首先在OrderMapper.xml映射文件中添加如下<select>元素:

                          <select id="getOrderListResultMap" resultMap="order_list_result_map">
                              select id,user_id,number,createtime,note from orders;
                          </select>
                           

                            使用resultMap指定上边定义的order_list_result_map。
                            接着定义resultMap。由于上边的OrderMapper.xml映射文件中sql查询列和Orders.java类属性不一致,因此需要定义resultMap:order_list_result_map将sql查询列和Orders.java类属性对应起来。

                            <resultMap type="orders" id="order_list_result_map">
                                <!-- id是主键的映射,其中property是pojo中主键的属性,column是返回结果中主键的列 -->
                                <id property="id" column="id" />
                                <!-- 普通列使用result映射 -->
                                <result property="userId" column="user_id" />
                                <result property="number" column="number" />
                                <result property="createtime" column="createtime" />
                                <result property="note" column="note" />
                            </resultMap>
                             
                              • type:指resultMap要映射成的数据类型(返回结果映射的pojo,可以使用别名)。
                              • <id />:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />
                              • property:表示Orders类的属性。
                              • column:表示sql查询出来的字段名。
                                column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。
                              • <result />:普通列使用result标签映射。

                              然后在OrderMapper接口添加如下方法:

                              List<Orders> getOrderListResultMap();
                               
                              • 1

                              最后在OrderMapperTest单元测试类中添加如下测试方法:

                              @Test
                              public void testGetOrderListResultMap() {
                                  SqlSession sqlSession = sqlSessionFactory.openSession();
                                  OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
                                  List<Orders> orderList = orderMapper.getOrderListResultMap();
                                  for (Orders orders : orderList) {
                                      System.out.println(orders);
                                  }
                                  sqlSession.close();
                              }
                               

                                同样在testGetOrderListResultMap方法中的以下代码处打一个断点:

                                for (Orders orders : orderList) {
                                 
                                • 1

                                然后以Debug模式运行该方法,可发现查询出来的每一个Orders对象中的userId属性都有值了。

                                动态sql

                                我们可通过mybatis提供的各种标签方法实现动态拼接sql。

                                if

                                现有这样一个需求:传递pojo类综合查询用户信息,更具体地说就是我们使用用户的id和username能更加灵活地查询用户信息。
                                为了解决这个需求,我们就要使用<if>标签了。首先在UserMapper.xml映射文件中添加如下<select>元素:

                                <select id="findUserList" parameterType="user" resultType="user">
                                    select * from user
                                    where 1=1
                                    <if test="id!=null">
                                        and id=#{id}
                                    </if>
                                    <if test="username!=null and username!=''">
                                        and username like '%${username}%'
                                    </if>
                                </select>
                                 

                                  注意:

                                  1. username要做不等于空字符串的校验。
                                  2. User类中id属性的类型要改为Integer包装类型,因为int类型的id是不可能为null的!

                                  然后在UserMapper接口添加如下方法:

                                  List<User> findUserList(User user);
                                   
                                  • 1

                                  最后在UserMapperTest单元测试类中添加如下测试方法:

                                  @Test
                                  public void testFindUserList() {
                                      SqlSession sqlSession = sqlSessionFactory.openSession();
                                      // 获得mapper代理对象
                                      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                                      // 设置查询条件
                                      User user = new User();
                                      // user.setId(10);
                                      user.setUsername("张");
                                      // 执行查询
                                      List<User> userList = userMapper.findUserList(user);
                                      for (User user2 : userList) {
                                          System.out.println(user2);
                                      }
                                      sqlSession.close();
                                  }
                                   

                                    读者可试着给User对象只为id属性赋值,或者只为username属性赋值,又或者两者同时赋值。

                                    where

                                    UserMapper.xml映射文件中如下<select>元素:

                                    <select id="findUserList" parameterType="user" resultType="user">
                                        select * from user
                                        where 1=1
                                        <if test="id!=null">
                                            and id=#{id}
                                        </if>
                                        <if test="username!=null and username!=''">
                                            and username like '%${username}%'
                                        </if>
                                    </select>
                                     

                                      也可使用<where>标签写为:

                                      <select id="findUserList" parameterType="user" resultType="user">
                                          select * from user
                                          <where>
                                              <if test="id!=null">
                                                  and id=#{id}
                                              </if>
                                              <if test="username != null and username != ''">
                                                  and username like '%${username}%'
                                              </if>
                                          </where>
                                      </select>
                                       

                                        <where />可以自动处理第一个and。

                                        foreach

                                        现有这样一个需求:传入多个id查询用户信息。如若编写sql语句,可用下边两个sql实现:

                                        1. SELECT * FROM USER WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
                                        2. SELECT * FROM USER WHERE username LIKE '%张%' id IN (10,89,16)

                                        为了解决这个需求,首先在QueryVo类中定义List属性ids存储多个用户id,并添加getter/setter方法,如下:

                                        public class QueryVo {
                                        
                                            private User user;
                                            private List<Integer> ids;
                                        
                                            public List<Integer> getIds() {
                                                return ids;
                                            }
                                        
                                            public void setIds(List<Integer> ids) {
                                                this.ids = ids;
                                            }
                                        
                                            public User getUser() {
                                                return user;
                                            }
                                        
                                            public void setUser(User user) {
                                                this.user = user;
                                            }
                                        
                                        }
                                         

                                          然后在UserMapper.xml映射文件中添加如下<select>元素:

                                          <!-- 动态sql foreach测试 -->
                                          <select id="findUserByIds" parameterType="queryvo" resultType="user">
                                              SELECT * FROM `user` 
                                              <where>
                                                  <!-- and id IN(1,10,20,21,31) -->
                                                  <foreach collection="ids" item="id" open="and id in(" close=")" separator=",">
                                                      #{id}
                                                  </foreach>
                                              </where>
                                          </select>
                                           

                                            向sql中传递数组或List,mybatis将使用foreach解析。
                                            接着在UserMapper接口添加如下方法:

                                            List<User> findUserByIds(QueryVo queryVo);
                                             
                                            • 1

                                            最后在UserMapperTest单元测试类中添加如下测试方法:

                                            @Test
                                            public void testFindUserByIds() {
                                                SqlSession sqlSession = sqlSessionFactory.openSession();
                                                // 获得mapper代理对象
                                                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                                                // 设置查询条件
                                                QueryVo queryVo = new QueryVo();
                                                List<Integer> ids = new ArrayList<Integer>();
                                                ids.add(1);
                                                ids.add(10);
                                                ids.add(16);
                                                ids.add(22);
                                                queryVo.setIds(ids);
                                                // 执行查询
                                                List<User> userList = userMapper.findUserByIds(queryVo);
                                                for (User user2 : userList) {
                                                    System.out.println(user2);
                                                }
                                                sqlSession.close();
                                            }
                                             

                                              sql片段

                                              sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:

                                              <select id="findUserList" parameterType="user" resultType="user">
                                                  select * from user
                                                  <where>
                                                      <if test="id!=null">
                                                          and id=#{id}
                                                      </if>
                                                      <if test="username != null and username != ''">
                                                          and username like '%${username}%'
                                                      </if>
                                                  </where>
                                              </select>
                                               

                                                将where条件抽取出来,同时我们也可将要查询的字段抽取出来。

                                                <sql id="find_user_list_where">
                                                    <where>
                                                        <if test="id!=null">
                                                            and id=#{id}
                                                        </if>
                                                        <if test="username != null and username != ''">
                                                            and username like '%${username}%'
                                                        </if>
                                                    </where>
                                                </sql>
                                                
                                                <sql id="user_field_list">
                                                    id,username,birthday,sex,address
                                                </sql>
                                                 

                                                  使用include引用:

                                                  <select id="findUserList" parameterType="user" resultType="user">
                                                      select <include refid="user_field_list"/> from user
                                                      <include refid="find_user_list_where"/>
                                                  </select>
                                                   

                                                    注意:如果引用其它mapper.xml映射文件的sql片段,则在引用时需要加上namespace,如下:

                                                    <include refid="namespace.sql片段"/>
                                                     
                                                    • 1
                                                    					<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-778f64ae39.css" rel="stylesheet">
                                                                </div>
                                                    
                                                    评论
                                                    添加红包

                                                    请填写红包祝福语或标题

                                                    红包个数最小为10个

                                                    红包金额最低5元

                                                    当前余额3.43前往充值 >
                                                    需支付:10.00
                                                    成就一亿技术人!
                                                    领取后你会自动成为博主和红包主的粉丝 规则
                                                    hope_wisdom
                                                    发出的红包
                                                    实付
                                                    使用余额支付
                                                    点击重新获取
                                                    扫码支付
                                                    钱包余额 0

                                                    抵扣说明:

                                                    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
                                                    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

                                                    余额充值