MyBatis-XxxxMapper.xml-SQL 映射文件

  |   0 评论   |   0 浏览

MyBatis-XxxxMapper.xml-SQL 映射文件

1.官方文档

1.文档地址

https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

2.XxxMapper.xml-基本介绍

1、MyBatis 的真正强大在于它的语句映射(在 XxxMapper.xml 配置), 由于它的异常强大, 如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。 MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

2、SQL 映射文件常用的几个顶级元素(按照应被定义的顺序列出)

cache – 该命名空间的缓存配置。
cache-ref – 引用其它命名空间的缓存配置。 
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。 
parameterType - 将会传入这条语句的参数的类全限定名或别名
sql – 可被其它语句引用的可重用语句块。
insert – 映射插入语句。
update – 映射更新语句。
delete – 映射删除语句。 
select – 映射查询语句。

3.XxxMapper.xml-详细说明

1.新建 Module xml-mapper

image-20220703173445481

1、在原来的项目中,新建 xml-mapper 项目演示 xml 映射器的使用

2、新建 Module 后,先创建需要的包,再将需要的文件/资源拷贝过来(这里我们拷贝 Monster.java、resources/jdbc.properties 和 mybatis-config.xml)

3、创建 MonsterMapper.java MonsterMapper.xml 和 MonsterMapperTest.java

2.基本使用

  1. insert、delete、update、select 分别对应增删改查的方法和 SQL 语句的映射.
  2. 如何获取到刚刚添加的 Monster 对象的 id 主键
<!--配置save
     1. id="save" 就是接口的方法名
     2. parameterType="com.llp.entity.Monster" 放入的形参的类型
     3. 注意"com.llp.entity.Monster" 可以简写
     4. 写入sql语句=> 现在sqlyog 写完成-测试通过,再拿过来
     5. (`age`, `birthday`, `email`, `gender`, `name`, `salary`) 表的字段
     6. (#{age}, #{birthday}, #{email}, #{gender}, #{name}, #{salary}) 是从传入的monster对象属性值
     7. 这里 #{age} age 对应monster对象的属性名,其它一样
 -->
<insert id="save" parameterType="com.llp.entity.Monster" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO `monster`
    (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
    VALUES (#{age}, #{birthday}, #{email}, #{gender}, #{name}, #{salary})
</insert>

3. parameterType(输入参数类型)

● parameterType(输入参数类型)

  1. 传入简单类型,比如按照 id 查 Monster(前讲过)
  2. 传入 POJO 类型,查询时需要有多个筛选条件
  3. 当有多个条件时,传入的参数就是 Pojo 类型的 Java 对象,比如这里的 Monster 对象
  4. 当传入的参数类是 String 时,也可以使用 ${} 来接收参数

● parameterType-应用案例

案例 1:请查询 id = 1 或者 name = '牛魔王' 的妖怪

案例 2:请查询 name 中 包含 "牛魔王" 的妖怪

1.修改 MonsterMapper.java, 增加方法接口

public interface MonsterMapper {

    //通过 id 或者名字查询
    List<Monster> findMonsterByNameORId(Monster monster);


    // 查询名字中含义'精'妖怪
    List<Monster> findMonsterByName(@Param("name") String name);
}
  1. 修改 MonsterMapper.xml
<!--配置别名-->
<!--<typeAliases>-->
    <!--<typeAlias type="com.llp.entity.Monster" alias="Monster"/>-->
    <!--
       如果一个包下有很多的类,我们可以直接引入包,这样
       该包下面的所有类名,可以直接使用
   -->
    <!--<package name="com.llp.entity"/>-->
<!--</typeAliases>-->
<!--我们在mybatis-config.xml中配置了别名包扫描,resultType也可以直接写实体 resultType=Monster -->
<select id="findMonsterByNameORId" resultType="com.llp.entity.Monster">
    select * from monster where name=#{name} or id = #{id}
</select>

<!--
 这里我们如果使用like '%#{name}%'的方式会抛出类似下面的异常
Cause: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).

1.糊查询的使用 取值 需要 ${value}  或者  CONCAT('%', #{value}, '%') 的方式
2.MyBatis中sql用双引号和单引号都是可以,建议使用单引号 like ""%${name}%" 
-->
<select id="findMonsterByName" resultType="com.llp.entity.Monster">
    select * from monster where name like '%${name}%'
</select>
  1. 修改 MonsterMapperTest.java ,完成测试
@Test
public void findMonsterByNameORId(){
    Monster monster = new Monster();
    monster.setName("牛魔王");
    monster.setId(1);
    List<Monster> monsterList = monsterMapper.findMonsterByNameORId(monster);
    for (Monster m : monsterList) {
        System.out.println(m);
    }
}

@Test
public void findMonsterByName(){
    List<Monster> monsterList = monsterMapper.findMonsterByName("牛魔王");
    for (Monster monster : monsterList) {
        System.out.println(monster);
    }
}

image-20220703175900595

4.传入 HashMap

● 传入 HashMap(重点)

  1. HashMap 传入参数更加灵活,比如可以灵活的增加查询的属性,而不受限于 Monster 这 个 Pojo 属性本身
  2. 演示如何遍历一个 List<Map<String,Object>> 的数据类型

● 传入 HashMap- 应用实例

要求:声明一个方法,按传入参数是 HashMap 的方式,查询 id >=1 并且 salary 大于 40 的所有妖怪

  1. 修改 MonsterMapper.java
//查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
List<Monster> findMonsterByMap(Map<String, Object> map);

2.修改 MonsterMapper.xml

<!--查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
    注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
-->
<select id="findMonsterByMap" resultType="com.llp.entity.Monster">
    select * from monster where id>= #{id} and salary > #{salary}
</select>
  1. 修改 MonsterMapperTest.java
@Test
public void findMonsterByMap(){
    Map<String,Object> map = new HashMap<>();
    // 注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
    map.put("id",1);
    map.put("salary",40);
    List<Monster> monsterList = monsterMapper.findMonsterByMap(map);
    for (Monster monster : monsterList) {
        System.out.println(monster);
    }
}

image-20220703182902995

● 传入和返回 HashMap- 应用实例

1.修改 MonsterMapper.java

//查询 id >=1 并且 salary 大于 40, 要求传入的参数是 HashMap 返回的也是Map
 List<Map<String, Object>> findMonsterByMapAndReturnMap(Map<String, Object> map);

2.修改 MonsterMapper.xml

<!--查询 id >= 1 并且 salary 大于 40, 要求传入的参数是 HashMap
    注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
-->
<select id="findMonsterByMapAndReturnMap" resultType="java.util.Map">
    SELECT id,name FROM monster WHERE id >= #{id} AND salary > #{salary}
</select>

3.测试

@Test
public void findMonsterByMapAndReturnMap(){
    Map<String,Object> map = new HashMap<>();
    // 注意:如果入参是map,这里的id、salary在map中必须存在对应的key,mybatis才能m匹配#{id} #{salary}
    map.put("id",1);
    map.put("salary",40);
    List<Map<String, Object>> mapList = monsterMapper.findMonsterByMapAndReturnMap(map);
    for (Map<String, Object> monsterMap : mapList) {
        System.out.println(monsterMap);
        //遍历monsterMap去除属性和值
        for (String key : monsterMap.keySet()) {
            System.out.println(key+"="+monsterMap.get(key));
        }
        for (Map.Entry<String, Object> entry : monsterMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
        }
        
    }
}

5.resultMap(结果集映射)

1.应用实例

● 基本介绍

当实体类的属性和表的字段名字不一致时,我们可以通过 resultMap 进行映射,从而屏蔽 实体类属性名和表的字段名的不同.

● 案例演示

  1. 创建表 user
-- 创建的 user 表
CREATE TABLE `user` (
	`user_id` INT NOT NULL AUTO_INCREMENT,
	`user_email` VARCHAR ( 255 ) DEFAULT '',
	`user_name` VARCHAR ( 255 ) DEFAULT '',
PRIMARY KEY ( `user_id` ) 
) CHARSET = utf8

2.创建src\main\java\com\llp\entity\User.java,这里我们故意的不适用标准的小驼峰方式,让实体和数据库字段不匹配

@Data
public class User {
    private Integer user_id;
    private String username;
    private String useremail;
}

3.创建src\main\java\com\llp\mapper\UserMapper.java

public interface UserMapper {

    //添加方法
    void addUser(User user);

    //查询所有的 User
    List<User> findAllUser();

}

4.创建src\main\java\com\llp\mapper\UserMapper.xml

<mapper namespace="com.llp.mapper.UserMapper">
  <!--
    1、配置方法public void addUser(User user);
    2、完成添加用户的任务, 注意这里user属性和表的字段名不一致
    -->
    <insert id="addUser" parameterType="User">
        INSERT INTO `user` (`user_email`,`user_name`)
        VALUE (#{useremail}, #{username})
    </insert>


    <!--
    1. 配置方法public List<User> findAllUser();
    2. 返回所有的user信息
    3. 按照传统的方式完成,会出现什么问题?=> 如果对象属性名和表字段相同时,就会设置值, 如果不同, 就会是默认值
    4. 我们可以使用resultMap来解决
    5. resultMap : 表示我们要定义一个resultMap
    6. id="findAllUserMap"  => id 就是程序员指定的resultMap id ,后面通过id可以使用他
    7. type="User" , 就是你需要返回的对象类型
    8. result column="user_email" property="useremail":  column="user_email" 表的字段名, property="useremail" 对象属性名
    9. resultMap="findAllUserMap" 表示使用我们定义的 resultMap , 通过id关联
    -->
    <resultMap id="findAllUserMap" type="User">
        <result column="user_email" property="useremail"/>
        <result column="user_name" property="username"/>
    </resultMap>
    <select id="findAllUser" resultMap="findAllUserMap">
        SELECT * FROM `user`
    </select>

    <!--使用表字段别名,来解决表的字段名和对象属性名,不一致问题, 可以用,但是我们仍然推荐使用resultmap-->
    <!--<select id="findAllUser" resultType="User">-->
    <!--    SELECT user_id ,user_name AS username,user_email AS useremail FROM `user`-->
    <!--</select>-->

</mapper>

5.创建src\test\java\com\llp\mapper\UserMapperTest.java

public class UserMapperTest {
    private SqlSession sqlSession;
    private UserMapper userMapper;

    /**
     * 当方法标注 @Before, 表示在执行你的目标测试方法前,会先执行该方法
     */
    //编写方法完成初始化
    @Before
    public void init() {
        this.sqlSession = MyBatisUtil.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(sqlSession);
    }


    @Test
    public void saveUser(){
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setUser_id(i);
            user.setUseremail("123@qq.com");
            user.setUsername("wukong");
            userMapper.addUser(user);
            //新增、删除、修改 mybatis默认开启事务需要手动提交
            if(sqlSession !=null){
                sqlSession.commit();
            }
        }
    }


    @Test
    public void findAllUser(){
        List<User> allUser = userMapper.findAllUser();
        for (User user : allUser) {
            System.out.println(user);
        }
    }

    /**
     * 当方法标注 @After, 表示在执行你的目标测试方法后,会先执行该方法
     */
    @After
    public void close() {
        if (sqlSession != null) {
            //Returned connection 1412925683 to pool.
            sqlSession.close();
        }
    }
}

测试结果

image-20220703185403229

2.注意事项和细节

1、解决表字段和对象属性名不一致, 也支持使用字段别名

<!-- 实现 findAllUser【使用别名 屏蔽属性名和字段名不一致 可以用,但是复用性不 ok 】 -->

<select id="findAllUser" resultType="User"> SELECT user_id,user_name AS username, user_email AS useremail FROM user </select>

2、说明:如果是 MyBatis-Plus 处理就比较简单, 可以使用 注解@TableField 来解决 实体字段名和表字段名不一致的问题,还可以使用@TableName 来解决 实体类名和表名 不一致的问题


标题:MyBatis-XxxxMapper.xml-SQL 映射文件
作者:llp
地址:https://llinp.cn/articles/2022/07/03/1656845842511.html