MyBatis系列三: XxxMapper.xml-SQL映射文件

XxxMapper.xml-SQL映射文件

官方文档

文档地址: https://mybatis.org/mybatis-3/zh_CN/sqlmap-xml.html

基本介绍

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

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

cache - 该命名空间的缓存配置
cache-ref - 引用其它命名空间的缓存配置
resultMap - 描述如何从数据集结果集中加载对象, 是最复杂也是最强大的元素
parameterType - 将会传入这条语句的参数的类全限定名或别名

sql - 可被其它语句引用的可重复的语句块.
insert - 映射插入语句
update - 映射更新语句
delete - 映射删除语句
select - 映射查询语句

详细说明

1.在原来的mybatis项目中, 新建xml-mapper子项目 [参考], 演示xml映射器的使用

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

3.拷贝MonsterMapper.java, MonsterMapper.xmlMonsterMapperTest.java, 做一个比较 干净的讲解环境

基本使用

1.insert, delete, update, select这个我们在前面学习过, 分别对应增删改查的方法和SQL语句的映射

2.如何获取到刚刚添加的Monster对象的id主键 [前面讲解过了]

xml 复制代码
<insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO `monster` (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
    VALUES (#{age}, #{birthday}, #{email}, #{gender}, #{name}, #{salary})
</insert>

parameterType(输入参数类型)

●parameterType(输入参数类型)

1.传入简单类型, 比如按照idMonster(前面学过)

2.传入POJO类型, 查询时需要有多个筛选条件

3.当有多个条件时, 传入的参数就是Pojo类型的Java对象, 比如这里的Monster对象

4.当传入的参数类是String时, 也可以使用 ${} 来接收参数

●parameterType-应用案例

案例1: 请查询 id = 1 或者 name = 大象精 的妖怪

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

●代码实现

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

java 复制代码
public interface MonsterMapper {
    //通过id 或者 名字查询
    public List<Monster> findMonsterByNameOrId(Monster monster);

    //查询名字中含有牛魔王的妖怪
    public List<Monster> findMonsterByName(String name);
}

2.修改MonsterMapper.xml

xml 复制代码
<mapper namespace="com.zzw.mapper.MonsterMapper">
    <!--
    1. 配置/实现public List<Monster> findMonsterByNameOrId(Monster monster);
    2. 通过id 或者 名字查询
    3. `id` = #{id} `id`表示表的字段名 #{id}中的id表示你传入的Monster对象的属性名
    -->
    <select id="findMonsterByNameOrId" parameterType="Monster" resultType="Monster">
        SELECT * FROM `monster` WHERE `id` = #{id} OR `name` = #{name}
    </select>

    <!--
    1. 配置/实现public List<Monster> findMonsterByName(Monster monster);
    2. 查询名字中 含有 "牛魔王" 的妖怪 - 模糊查询`
    3. 模糊查询的使用 取值需要 ${value} 取值
    -->
    <select id="findMonsterByName" parameterType="String" resultType="Monster">
        SELECT * FROM `monster` WHERE `name` LIKE '%${name}%'
    </select>
</mapper>

3.修改MonsterMapperTest.java, 进行测试

java 复制代码
public class MonsterMapperTest {
    //属性
    private SqlSession sqlSession;
    private MonsterMapper monsterMapper;

    //编写方法完成初始化
    @Before
    public void init() {
        //获取到sqlSession
        sqlSession = MyBatisUtils.getSqlSession();
        //获取到MonsterMapper对象 monsterMapper=class com.sun.proxy.$Proxy7 代理对象
        //, 底层是使用了动态代理机制, 后面我们自己实现mybatis底层机制时, 会讲到
        monsterMapper = sqlSession.getMapper(MonsterMapper.class);
        System.out.println("monsterMapper=" + monsterMapper.getClass());
    }

    @Test
    public void findMonsterByNameOrId(){
        Monster monster = new Monster();
        monster.setId(1);
        monster.setName("大象精");
        List<Monster> monsters =
                monsterMapper.findMonsterByNameOrId(monster);

        for (Monster m : monsters) {
            System.out.println("m--" + m);
        }

        if (sqlSession != null) {
            sqlSession.close();
        }

        System.out.println("查询成功");
    }

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

        if (sqlSession != null) {
            sqlSession.close();
        }

        System.out.println("查询成功");
    }
}

传入HashMap

●传入HashMap(重点)

1.HashMap传入参数更加灵活, 比如可以灵活地增加查询的属性, 而不受限于Monster这个Pojo属性本身

2.演示如何遍历一个List<Map<String, Object>>的数据类型

●传入HashMap - 应用实例1

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

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

java 复制代码
//查询 id > 10 并且 salary > 40的所有妖怪
public List<Monster> findMonsterByIdAndSalary_ParameterHashMap(Map<String, Object> map);

2.修改MonsterMapper.xml

xml 复制代码
<!--
1. 配置/实现public List<Monster> findMonsterByIdAndSalary_ParameterHashMap(Map<String, Objects> map);
2. 查询 id > 10 并且 salary > 40的所有妖怪
3. 如果是以map形式传入参数, 当你这样写条件 `id` > #{id} 表示你的map 中有一个k-v 中 key为id
-->
<select id="findMonsterByIdAndSalary_ParameterHashMap" parameterType="map" resultType="Monster">
    SELECT * FROM `monster` WHERE `id` > #{id} AND `salary` > #{salary}
</select>

3.修改MonsterMapperTest.java, 进行测试

java 复制代码
@Test
public void findMonsterByIdAndSalary_ParameterHashMap() {
    Map<String, Object> map = new HashMap<>();
    map.put("id", 10);
    map.put("salary", 40);
    List<Monster> monsters =
            monsterMapper.findMonsterByIdAndSalary_ParameterHashMap(map);

    for (Monster monster : monsters) {
        System.out.println("monster--" + monster);
    }

    if (sqlSession != null) {
        sqlSession.close();
    }

    System.out.println("查询成功");
}

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

要求: 将上面的方法改成返回参数也是HashMap的类型

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

java 复制代码
//查询 id > 10 并且 salary > 40, 要求传入的参数是HashMap
public List<Map<String, Object>>
        findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(Map<String, Object> map);

2.修改MonsterMapper.xml

xml 复制代码
<!--
1. 配置/实现public List<Map<String, Object>>
        findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap
2. 查询 id > 10 并且 salary > 40, 要求传入的参数是HashMap
-->
<select id="findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap" parameterType="map"
        resultType="map">
    SELECT * FROM `monster` WHERE `id` > #{id} AND `salary` > #{salary}
</select>

3.修改MonsterMapperTest.java, 进行测试

java 复制代码
@Test
public void findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap() {
    Map<String, Object> map = new HashMap<>();
    map.put("id", 10);
    map.put("salary", 40);
    List<Map<String, Object>> maps =
            monsterMapper.findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(map);

    //取出返回的结果-以map的形式取出
    //回顾java基础, map遍历
    for (Map<String, Object> monsterMap : maps) {
        //System.out.println("monsterMap--" + monsterMap);

        //遍历monsterMap(方式1), 取出属性和对应值
        //Set<String> keySet = monsterMap.keySet();
        //for (String key : keySet) {
        //    Object value = monsterMap.get(key);
        //    System.out.println(key + "=>" + value);
        //}

        //遍历monsterMap(方式2), 取出属性和对应值
        Set<Map.Entry<String, Object>> entries = monsterMap.entrySet();
        for(Map.Entry<String, Object> entry : entries) {
            System.out.println(entry.getKey() + "=>" + entry.getValue());
        }
        System.out.println("==================================");
    }

    if (sqlSession != null) {
        sqlSession.close();
    }

    System.out.println("查询成功");
}

resultMap(结果集映射)

●基本介绍

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

●案例演示

1.创建表user

sql 复制代码
-- 创建表 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.创建实体类com.zzw.entity.User

java 复制代码
public class User {
    private Integer user_id;
    private String username;
    private String useremail;

	//setter, getter, toString方法
}

3.创建com.zzw.mapper.UserMapper.java

java 复制代码
public interface UserMapper {
    //添加方法
    public void addUser(User user);

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

4.创建com.zzw.mapper.UserMapper.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--解读
    1. 这是一个mapper xml 文件
    2. 该文件可以去实现对应的接口的方法
    3. namespace 指定该xml文件和哪个接口对应!!!
-->
<mapper namespace="com.zzw.mapper.UserMapper">
    <!--
    1. 配置/实现public void addUser(User user);
    2. 完成添加用户的任务,注意这里
    -->
    <select id="addUser" parameterType="User">
        INSERT INTO `user` (`user_email`, `user_name`)
        VALUES (#{useremail}, #{username})
    </select>

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

5.测试com.zzw.mapper.UserMapperTest

java 复制代码
public class UserMapperTest {

    //属性
    private SqlSession sqlSession;
    private UserMapper userMapper;

    //初始化
    @Before
    public void init() {
        sqlSession = MyBatisUtils.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void addUser() {
        User user = new User();
        user.setUsername("jack");
        user.setUseremail("jack@163.com");

        userMapper.addUser(user);

        //如果是增删改, 需要提交事务
        if (sqlSession != null) {
            sqlSession.commit();
            sqlSession.close();
        }

        System.out.println("增加成功");
    }

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

        if (sqlSession != null) {
            sqlSession.close();
        }

        System.out.println("查询成功");
    }
}

●注意事项和细节

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

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

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

相关推荐
高级程序源14 分钟前
springboot学生档案信息管理系统-计算机毕业设计源码96509
java·spring boot·spring·eclipse·mybatis·idea
白菜!!!21 分钟前
SQL INSERT批量插入方式
数据库·sql·mysql·mybatis
屿小夏.23 分钟前
【SQL】已解决:SQL错误(15048): 数据兼容级别有效值为100、110或120
数据库·sql·oracle
苏生Susheng3 小时前
【Oracle】Oracle常用语句大全
java·数据库·sql·mysql·oracle·sql语句·数据库语法
dot.Net安全矩阵3 小时前
.NET 漏洞分析 | 某ERP系统存在SQL注入
数据库·sql·安全·web安全·矩阵·.net
六月的雨__4 小时前
二手物品交易小程序的设计
java·sql·学习·小程序
dot.Net安全矩阵5 小时前
.NET 漏洞情报 | 某整合管理平台SQL注入
数据库·sql·安全·矩阵·.net
都适、隶仁ミ6 小时前
SQL注入工具Sqlmap
linux·网络·数据库·sql·安全·网络安全·系统安全
Anpedestrian6 小时前
Mybatis中支持缓存的query与不支持缓存的query
java·缓存·mybatis
测试开发-学习笔记6 小时前
sql查询练习
数据库·sql