zoukankan      html  css  js  c++  java
  • 【测试开发】知识点mybatis,XML 映射文件介绍

    MyBatis 的真正强大在于它的语句映射,它指导着 Mybatis 如何进行数据库的增删改查。在之前的demo当中已简单使用过,写sql的那个XML 文件就是映射文件。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.pingguo.bloomtest.dao.UserMapper">
        <select id="getUserById" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
          select * from user where id = #{id}
        </select>
    </mapper>
    

    SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

    • cache – 该命名空间的缓存配置。
    • cache-ref – 引用其它命名空间的缓存配置。
    • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
    • parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
    • sql – 可被其它语句引用的可重用语句块。
    • insert – 映射插入语句。
    • update – 映射更新语句。
    • delete – 映射删除语句。
    • select – 映射查询语句。

    不过,先来看下增删改查。

    一、增删改查速览

    我继续在接口里新增几个方法(查询已有):

    public interface UserMapper {
        // 查询
        User getUserById(Integer id);
        // 新增
        void addUser(User user);
        // 修改
        void updateUser(User user);
        // 删除
        void deleteUser(Long id);
    }
    

    在映射文件UserMapper.xml中,使用insertupdatedelete标签来写对应方法的sql:

    <!--新增-->
    <insert id="addUser">
        insert into user(username, password, createTime, updateTime)
        values(#{username}, #{password}, #{createTime}, #{updateTime})
    </insert>
    
    <!--更新-->
    <update id="updateUser">
        update user
          set username=#{username}, password=#{password}, createTime=#{createTime}, updateTime=#{updateTime}
          where id=#{id}
    </update>
    
    <!--删除-->
    <delete id="deleteUser">
        delete from user where id=#{id}
    </delete>
    

    另外,mybatis 允许增删改直接定义如下的返回值:Integer、Long、Boolean。那么接口里定义的方法就可以写成这样:

    public interface UserMapper {
        // 查询
        User getUserById(Integer id);
        // 新增
        boolean addUser(User user);
        // 修改
        boolean updateUser(User user);
        // 删除
        boolean deleteUser(Long id);
    }
    

    addUser方法来说,新增成功之后返回的就是true

    在测试类里可以测试下上面几个方法,这里贴出来测试一下新增:

    @Test
    void test3() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        // 获取到的 SqlSession 不会自动提交数据
        SqlSession session = sqlSessionFactory.openSession();
        User newUser = new User();
        newUser.setUsername("新用户1");
        newUser.setPassword("111111");
        newUser.setCreateTime(new Date());
        newUser.setUpdateTime(new Date());
        try {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            userMapper.addUser(newUser);
            // 需要这里手动提交
            session.commit();
        } finally {
            session.close();
        }
    }
    

    注意这里sqlSessionFactory.openSession()不会自动提交数据,需要session.commit()手动提交。如果需要自动提交,里面传入true即可:

    sqlSessionFactory.openSession(true)
    

    image.png

    新增成功。

    image.png

    其他几个也成功通过测试。

    二、insert获取自增主键的值

    mysql 的自增主键,mybatis 也可以获取到,只需要添加一个属性useGeneratedKeys,默认是false

    那获取到的主键值,可以通过keyProperty将这个值封装给 Javabean 的某个属性,比如User类中的id

    <!--新增-->
    <insert id="addUser" useGeneratedKeys="true" keyProperty="id">
        insert into user(username, password, createTime, updateTime)
        values(#{username}, #{password}, #{createTime}, #{updateTime})
    </insert>
    

    可以在之前的测试方法里加一个打印,看下获取到的主键值:

    image.png

    成功获取到主键值为 12 。

    image.png

    查看数据库表里新增多数据主键就是 12 。

    image.png

    三、单个参数、多个参数、对象

    1. 单个参数

    拿上面根据 id 进行查询为例:

    <select id="getUserById" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where id = #{id}
    </select>
    

    使用#{参数名},mybatis就会正确取出参数值。

    当只有一个参数的时候,mybatis 不会做特殊处理,比如sql中的where条件是根据id来查询,但我就算写#{abc},也正常查询。

    2. 多个参数

    在接口UserMapper里再定义一个新的方法,里面传入多个参数:

    // 查询 使用多个参数
    User getUserByIdAndUsername(Integer id, String username);
    

    对应的增加sql映射:

    <select id="getUserByIdAndUsername" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
      select * from user where id = #{id} and username=#{username}
    </select>
    

    测试一下,可以正常查询。

    @Test
    void test2params() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);
        System.out.println(userMapper.getUserByIdAndUsername(3, "大周"));
    }
    

    3. 对象

    如果多个参数正好是我们业务逻辑的数据模型,那可以直接传入对象,比如POJO,通过#{属性名}取出属性值。

    如果多个参数没有对应的POJO,为了方便,也可以传入 Map 。

    在 UserMapper 里增加方法:

        User getUserByMap(Map<String, Object> map);
    

    sql 映射文件增加对应配置:

        <select id="getUserByMap" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
          select * from user where id = #{id} and username=#{username}
        </select>
    

    新增个测试方法,查询正常。

        @Test
        void testByMap() throws IOException {
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
            SqlSession session = sqlSessionFactory.openSession();
            UserMapper userMapper = session.getMapper(UserMapper.class);
    
            Map<String, Object> map = new HashMap<>();
            map.put("id", 3);
            map.put("username", "大周");
            System.out.println(userMapper.getUserByMap(map));
        }
    

    如果上述这种 map 还要经常使用,推荐编写一个TO(Transfer Object)数据传输对象。

    四、$ 和 # 取值

    mybatis 中是采用#{}${}都是可以取值的,但是两者还是有区别的,比如:

        <select id="getUserByIdAndUsername" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
          select * from user where id = ${id} and username=#{username}
        </select>
    

    我在这里把2个参数分别用了不同的方法来取值:${id}#{username},然后执行之前的测试函数,看下打印结果。

    区别就是:

    • #{},是以预编译形式,讲参数设置到 sql 语句中
    • ${},取出的值直接拼装在 sql 语句中,会存在一定的安全问题

    大多数情况下,我们都去使用#{}

    不过在某些情况下,还是会用到${}。比如一个工资表按照年份进行了拆分,表名前面是年份,那么要动态查询表的时候,年份就是个变量。

    表名是不能预编译的,所以不能使用#{}。对于这种原生JDBC不支持占位符的地方,就可以使用${}

    select * from ${year}_salary where xxx;
    

    再比如,用到排序,我想把排序的条件和升序降序可以动态的穿进来,也可以使用${}

    select * user order by ${age} ${desc_order};
    

    五、select 元素

    1. select 返回 list

    如果我定义了一个查询,返回的是一个 list。

        List<User> getUserByUsernameLike(String username);
    

    sql 映射文件这样写:

        <select id="getUserByLastNameLike" resultType="com.pingguo.bloomtest.pojo.User" databaseId="mysql">
          select * from user where username like #{username}
        </select>
    

    注意这里如果返回的是一个集合类型,resultType里要写集合中的类型。

    2. select 返回 map

    如果需要返回一条记录的 map,key 就是列名,value 就是对应的值。

    Map<String, Object> getUserByIdReturnMap(Integer id);
    

    sql 映射文件这样写:

        <select id="getUserByIdReturnMap" resultType="map">
            select * from user where id = #{id}
        </select>
    

    测试下,查询正常。

    如果需要封装多条记录比如Map<Integer, User>,key 是记录的主键,value 是记录封装后的 javabean 。

    Map<Integer, User> getUserByUsernameReturnMap(String username);
    

    sql 映射文件:

        <select id="getUserByUsernameReturnMap" resultType="com.pingguo.bloomtest.pojo.User">
            select * from user where username like #{username}
        </select>
    

    这里的返回类型还是 User,现在 value 有了,那么如何把主键作为 map 的 key 呢?

    使用注解@MapKey("id"),告诉 mybatis 使用哪个属性作为 key:

        @MapKey("id")
        Map<Integer, User> getUserByUsernameReturnMap(String username);
    

    测试一下:

    如果换成其他属性作为 key 也是可以的。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    s s r 多用户 简单配置
    iptables vsftp timeout
    透明控件的通用解决方案
    一个带有可选自定义框架的透明对话框类
    把你的框架窗口一个影子
    WinForms形成皮肤
    WPF加载启动画面
    酷,半透明和形状对话框与标准的控制Windows 2000及以上
    在MFC应用程序中创建web风格的GUI
    画在WinForms控制
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15647331.html
Copyright © 2011-2022 走看看