• [转] MyBatis的XxxMapper.xml 映射器的详解(六)


    上一章简单介绍了MyBatis的核心配置文件 SqlMapConfig.xml(五),如果没有看过,请观看上一章。

    一 . XxxMapper.xml 映射器的使用
    在MyBatis 中,将Dao层的接口与对应的Mapper.xml 配置文件进行组合使用,而不是以前的接口实现类处理。 这里着重讲解一下,这个配置文件的使用。 将XxxMapper.xml 放置在与接口XxxMapper.java 同级的目录下。

    一.一 Schema约束
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    1
    2
    当然,前面不要忘记 xml文件的头部。


    <?xml version="1.0" encoding="UTF-8"?>
    1
    2
    一.二 Mapper 根节点
    有一个根节点,是mapper, 里面只有一个属性, namespace, 命名空间。 后面跟的值一般为其所在的包路径,或者说是XxxMapper.java 接口所在的包路径。

    <mapper namespace="com.yjl.mapper.UserMapper" >
    1
    一.三 下属节点
    在根节点 mapper 下的节点有:

    select       最常用,最复杂的元素之一, 可以自定义参数,返回结果集。
    insert        插入语句 返回所影响的行数
    update        更新语句 返回所影响的行数
    delete        删除语句 返回所影响的行数
    sql        定义一部分sql,构成sql 片段,然后在各个语句中引用。
    resultMap        从结果集中来加载对象,最复杂也是最强大的元素,提供了映射的规则。
    cache        给定命名空间的缓存配置
    cache-ref        其他命名空间缓存配置的引用
    其中,有一个parameterMap ,已经被放弃使用了。

    二. Select 元素的配置
    数据库数据为:


    在以前的mapper 映射中:

    <select id="getById" parameterType="int" resultType="user">
    <!-- 设置别名 -->
    select * from user where id=#{id}
    </select>

    1
    2
    3
    4
    5
    select 下面有 id属性,parameterType 参数类型, resultType 结果类型属性等节点, 这些不同的节点表示不同的作用与意义。 除了这些之外,还有其他的节点属性。 只需要记住一些常见的节点即可。

    二.一 所属节点

    下面就开始讲解 select元素的常见使用。

    二.二 like 的用法查询记录的数量
    在UserMapper.java 接口中:

    public int countByName(String name);
    1
    在UserMapper.xml 配置中其对应的配置语句为:

    <!-- 传入参数查询数目 -->
    <select id="countByName" parameterType="string" resultType="int">
    <!--单个的,可以用value 来接收-->
    select count(*) from user where name like '${value}'
    </select>
    1
    2
    3
    4
    5
    测试方法为:

    @Test
    public void countByNameTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    int count=userMapper.countByName("%蝴蝶%");
    System.out.println("输出数目为:"+count);
    }
    1
    2
    3
    4
    5
    6
    7
    控制台显示为:

    缺点, 上面传入的参数 需要自己手动拼接 %% 连接符, 用户只需要传入参数即可。 真正的拼接,应该放在数据库去完成。 每个数据库都有自己对应的字符串拼接方式。 mysql 可以使用 concat() 函数, oracle 可以使用 || .

    <!-- 传入参数查询数目 -->
    <select id="countByName" parameterType="string" resultType="int">
    select count(*) from user where name like concat('%',#{name},'%')
    </select>
    1
    2
    3
    4
    上面是两个%%的形式,如果是前% 为 concat(’%’,#{name}), 后%为 concat(#{name},’%’);

    三. 传参 parameterType
    传参可以使用三种方式

    map 方式的传参(较旧的方式)
    注解@Param 的方式 (适用于参数较少的情况,且与实体属性无太太关联)
    实体对象bean 的方式 (适用于插入,更新 等与实体属性关联的,或者属性过多的时候,封装成bean传入)
    三.一 Map 形式的传参
    接口:

    //多个参数的时候。
    public List<User> findByNameAndSexMap(Map<String,Object> map);
    1
    2
    xml配置实现

    <!-- 查询多个参数的时候 ,map 的形式 parameterType='map' map为系统定义好的别名-->
    <select id="findByNameAndSexMap" parameterType="map" resultType="user">
    select * from user where name like concat('%',#{name},'%') and sex=#{sex}
    </select>
    1
    2
    3
    4
    测试方法:

    @Test
    public void findByNameAndSexMapTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    //定义参数
    Map<String,Object> paraMap=new HashMap<String,Object>();
    //key与xml 中配置的相同
    paraMap.put("name","蝴蝶");
    paraMap.put("sex","男");
    List<User> allList=userMapper.findByNameAndSexMap(paraMap);
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12


    要注意,map 中的key 键值 要与 sql语句中的#{值} 保持一致。

    三.二 @param 注解的方式
    接口:

    public List<User> findByNameAndSexAnnotation(@Param(value="name") String name,
    @Param(value="sex") String sex);
    1
    2
    sql语句配置:

    <!-- 查询多个参数的时候 ,注解 的形式, 没有参数类型 -->
    <select id="findByNameAndSexAnnotation" resultType="user">
    select * from user where name like concat('%',#{name},'%') and sex=#{sex}
    </select>
    1
    2
    3
    4
    测试方法, 为传参的形式

    @Test
    public void findByNameAndSexAnnotationTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<User> allList=userMapper.findByNameAndSexAnnotation("蝴蝶","男");
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7
    查询的结果与上面的一样。
    此时,sql语句中的值要与 注解的value 值相同,不一定要与方法中的形参的值相同。 适用于参数较少的情况,一般不超过5个。

    三.三 对象bean 的方式
    接口:

    public List<User> findByNameAndSexBean(User user);
    1
    sql语句:

    <!-- 实体对象bean的方式传参, 已经定义好别名user了 -->
    <select id="findByNameAndSexBean" parameterType="user" resultType="user">
    select * from user where name like concat('%',#{name},'%') and sex=#{sex}
    </select>
    1
    2
    3
    4
    测试方法:

    @Test
    public void findByNameAndSexBeanTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    User user=new User();
    user.setName("蝴蝶");
    user.setSex("男");
    List<User> allList=userMapper.findByNameAndSexBean(user);
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    查询的结果与上面的一致。

    三.四 三种传参方式的比较
    map 形式: map传入进去,是不知道key值是什么的,与sql 语句隔离了,导致了业务可读性的丧失,导致了后续的扩展与维护的困难,应当果断废弃这种方式。

    param 注解方式: 受参数个数的影响, 当n<=5 时,是最好的方式, 比java bean 还好,应该比java bean 更直观。 当n>5 时,多个参数调用会出现困难。

    java bean 方式: 当参数个数过多时使用。 >5 时。

    四. MyBatis 排序
    排序,用order by 进行排序。

    四.一 单个参数排序,用value 接收
    接口:

    public List<User> orderByAge(String age);
    1
    sql语句:

    <!-- 单个值排序,必须用value 进行接收 -->
    <select id="orderByAge" parameterType="string" resultType="user">
    <!-- select * from user order by ${value} desc -->
    select * from user order by ${value} desc
    </select>
    1
    2
    3
    4
    5
    测试方法:

    @Test
    public void orderByAgeTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<User> allList=userMapper.orderByAge("age");
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7


    四.二 多个参数排序 ,用注解方式传入
    接口:

    public List<User> orderByAgeAndId(@Param("age") String age,@Param("id") String id);
    1
    sql语句:

    <!-- 多个参数排序,可以用注解的方式 -->
    <select id="orderByAgeAndId" resultType="user">
    select * from user order by ${age} asc,${id} desc
    </select>
    1
    2
    3
    4
    测试方法:

    @Test
    public void orderByAgeAndIdTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<User> allList=userMapper.orderByAgeAndId("age","id");
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7


    五. 查询某些列的值
    在sql 语句的前面进行查询

    接口:

    public List<User> selectColumn(@Param(value="column1") String column1,
    @Param(value="column2") String column2,@Param(value="column3") String column3);
    1
    2
    sql语句:

    <select id="selectColumn" parameterType="map" resultType="user">
    <!-- 也可以写别名进行操作。 -->
    select ${column1},${column2},${column3} from user
    </select>
    1
    2
    3
    4
    测试方法:

    @Test
    public void selectColumnTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<User> allList=userMapper.selectColumn("name","sex","description");
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7


    只有要查询的列才有值。

    六. 查询结果 resultType
    六.一 最简单的形式查询
    数据表的字段要与实体Bean 的类属性保持一致。 如,在实体类中是:


    数据库中是:


    属性与字体一致的,可以进行相应的查询。

    接口:

    public List<User> findAll();
    1
    sql语句:

    <select id="findAll" resultType="user">
    select * from user
    </select>
    1
    2
    3
    测试方法:

    @Test
    public void findAllTest(){
    SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<User> allList=userMapper.findAll();
    allList.forEach(n ->System.out.println(n));
    }
    1
    2
    3
    4
    5
    6
    7


    如果数据表的名称与属性不一致的话,那么此时的查询呢? name和age不一致的情况。

    在数据表中,将原先的name 改成 u_name, age 改成u_age

    这个时候的查询呢?


    发现 name 和age 是没有值的, 因为无法正确的setter 和getter,所以是取不到值的。

    六.二 别名的方式查询,使表字段与类属性相同。
    <!-- 使用别名方式查询,令别名为 类属性 -->
    <select id="findAll" resultType="user">
    select id,u_name as name,u_age as age,sex,description from user
    </select>
    1
    2
    3
    4
    这个时候运行查询,是正确的。


    如果现在列名改成了,多个sql 语句查询时,都要设置别名,是不是太麻烦了呢?

    六.三 使用resultMap 来实现
    将结果集重新定义,定义成 resultMap 便可以了。 resultMap的详细用法,在一对一,一对多的关联关系中会仔细讲解。

    <!-- 定义结果类型的 map集合形式 -->
    <resultMap type="user" id="userResultMap">
    <!-- 指定主键用id, column为表列名, property 为类属性 -->
    <id property="id" column="id"/>
    <!-- 普通属性用 result -->
    <result property="name" column="u_name"/>
    <result property="sex" column="sex"/>
    <result property="age" column="_age"/>
    <result property="description" column="description"/>
    </resultMap>
    <!-- 使用resultMap方式查询 -->
    <select id="findAll" resultMap="userResultMap">
    select * from user
    </select>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    查询时,可以正确的查询出来值。

    resultMap 是很强大的元素, 以后会重点讲解。

    七. 插入的元素 insert 属性


    关于insert 的用法,可以参看第三章的知识。

    其中,插入的时候,可能并不是以1 进行插入,会自定义规则。 测试方法与前面的一样,sql接口是:

    <!-- 复杂的插入 -->
    <insert id="insertUser" parameterType="user" useGeneratedKeys="true"
    keyProperty="id">
    <selectKey keyProperty="id" resultType="int" order="BEFORE">
    select if(max(id) is null,1,max(id)+2) as newId from user
    </selectKey>
    insert into user(id,name,sex,age,description)
    values(#{id},#{name},#{sex},#{age},#{description})
    </insert>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    八. 更新的元素 update 和删除的元素 delete
    关于update 和delete的用法,可以参看第三章的知识。

    九. sql 元素
    在一个表中, 用select * from user 中 select * 是不太好的,实际开发中会用属性来代替, 如select id,u_name,sex,u_age,descrption from user 那么这个前面的查询会写很多个,如果改变了其中的一个字段,那么就要改变多个。 可以先将这个select id,u_name,sex,u_age,description 先当成sql 片段定义起来,然后再各个地方进行引用即可。

    九.一 普通单个引用
    <sql id="userSql">
    id,u_name,sex,u_age,description
    </sql>
    <select id="findAll" resultMap="userResultMap">
    select <include refid="userSql"/> from user
    </select>
    1
    2
    3
    4
    5
    6
    用sql元素来定义片段, 用 include 来引入片段。

    九.二 带参数的复杂引用
    <!-- 用的是$ 拼接符 -->
    <sql id="userSql">
    ${prefix}.id,${prefix}.u_name,${prefix}.sex,${prefix}.u_age,${prefix}.description
    </sql>
    <select id="findAll" resultType="user">
    select <include refid="userSql">
    <property name="prefix" value="t"/>
    </include>
    from user t
    </select>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    注意,用的是${}, 并不是以前常用的#{} .

    谢谢!!!
    ————————————————
    版权声明:本文为CSDN博主「两个蝴蝶飞」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/yjltx1234csdn/java/article/details/94588874

  • 相关阅读:
    不同包中继承关系访问protected内部类问题
    LinuxMM--MemoryHierarchy
    LinuxMM--Memory Pressure
    多态实验:基类——子类成员
    使用vue开发的word-cloud 词云组件
    基于mui.PopPicker的可多选下拉多选的底部弹出组件
    基于mui.popover的自定义底部弹出框-支持多选和搜索筛选的弹出列表组件改造以及mui.prompt添加自定义内容
    js去空 去除空格
    css+js控制文字显示行数,多出部分显示省略号
    使用vue开发自定义tabs标签页组件
  • 原文地址:https://www.cnblogs.com/eedc/p/12628464.html
Copyright © 2020-2023  润新知