XxxMapper.xml-SQL 映射文件
官方文档
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
XxxMapper.xml-基本介绍
MyBatis 的真正强大在于它的语句映射(在 XxxMapper.xml 配置),由于它的异常强大, 如 果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。 MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
SQL 映射文件常用的几个顶级元素(按照应被定义的顺序列出)
cache – 该命名空间的缓存配置。
cache-ref – 引用其它命名空间的缓存配置。
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
parameterType - 将会传入这条语句的参数的类全限定名或别名。
sql – 可被其它语句引用的可重用语句块。
insert – 映射插入语句。
update – 映射更新语句。
delete – 映射删除语句。
select – 映射查询语句。
XxxMapper.xml-详细说明
新建 Module xml-mapper
在原来的项目中,新建 xml-mapper 项目演示 xml 映射器的使用

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

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

package com.lzw.mapper;
import com.lzw.entity.Monster;
import com.lzw.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* @author LiAng
*/
public class MonsterMapperTest {
private SqlSession sqlSession;
private MonsterMapper monsterMapper;
@Before
public void init(){
sqlSession = MyBatisUtils.getSqlSession();
monsterMapper = sqlSession.getMapper(MonsterMapper.class);
System.out.println("monsterMapper = " + monsterMapper.getClass());
}
}
基本使用
- insert、delete、update、select 这个我们在前面讲解过,分别对应增删改查的方法和 SQL 语句的映射。
- 如何获取到刚刚添加的 Monster 对象的 id 主键 [前面使用过了]。
parameterType(输入参数类型)
- 传入简单类型,比如按照 id 查 Monster(前面使用过) 。
- 传入 POJO 类型,查询时需要有多个筛选条件。
- 当有多个条件时,传入的参数就是 Pojo 类型的 Java 对象,比如这里的 Monster 对象。
- 当传入的参数类是 String 时,也可以使用 ${} 来接收参数。
案例1:请查询 id = 1 或者 name = '白骨精' 的妖怪
修改 MonsterMapper.java
package com.lzw.mapper;
import com.lzw.entity.Monster;
import java.util.List;
import java.util.Map;
/**
* @author LiAng
*/
public interface MonsterMapper {
//通过id或者名字查询
public List<Monster> findMonsterByNameORId(Monster monster);
//查询名字中包含‘精’的妖怪
public List<Monster> findMonsterByName(String name);
}
修改 MonsterMapper.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">
<!--
1. 这是一个mapper xml 文件
2. 该文件可以去实现对应的接口的方法
3. namespace 指定该xml文件和哪个接口对应!!!
-->
<mapper namespace="com.lzw.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(String name);
2. 请查询 name 中 包含 "牛魔王" 的妖怪 - 是模糊查询
3. 模糊查询的使用 取值 需要 ${value} 取值
-->
</mapper>
修改 MonsterMapperTest.java
@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("操作成功");
}

案例2:请查询 name 中 包含 "牛魔王" 的妖怪
修改 MonsterMapper.xml
<!--
1. 配置/实现 public List<Monster> findMonsterByName(String name);
2. 请查询 name 中 包含 "牛魔王" 的妖怪 - 是模糊查询
3. 模糊查询的使用 取值 需要 ${value} 取值
-->
<select id="findMonsterByName" parameterType="String" resultType="Monster">
SELECT * FROM `monster` WHERE `name` LIKE '%${name}%'
</select>
修改 MonsterMapperTest.java
@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 传入参数更加灵活,比如可以灵活的增加查询的属性,而不受限于 Monster 这 个 Pojo 属性本身。
实例 1
声明一个方法,按传入参数是 HashMap 的方式,查询 id > 2 并且 salary 大于 40 的所有妖怪。
修改 MonsterMapper.java
//查询 id > 2 并且 salary 大于 40, 要求传入的参数是HashMap
public List<Monster> findMonsterByIdAndSalary_ParameterHashMap(Map<String, Object> map);
修改 MonsterMapper.xml
<!--
1. 配置/实现public List<Monster> findMonsterByIdAndSalary_ParameterHashMap(Map<String, Object> map);
2. id > 2 并且 salary 大于 40, 要求传入的参数是HashMap
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>
修改 MonsterMapperTest.java
@Test
public void findMonsterByIdAndSalary_ParameterHashMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("id", 1);
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("操作成功");
}

实例2
要求和实例1一样,并且 返回参数也以 HashMap 的类型。
修改 MonsterMapper.java
//查询 id > 2 并且 salary 大于 40, 要求传入的参数是HashMap
public List<Map<String, Object>> findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(Map<String, Object> map);
修改 MonsterMapper.xml
<!--
1. 配置/实现 public List<Map<String, Object>>
findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(Map<String, Object> map);
2. id > 2 并且 salary 大于 40, 要求传入的参数和返回的是HashMap
-->
<select id="findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap" parameterType="map" resultType="map">
SELECT * FROM `monster` WHERE `id` > #{id} AND `salary` > #{salary}
</select>
修改 MonsterMapperTest.java
@Test
public void findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("id", 1);
map.put("salary", 40);
List<Map<String, Object>> monsters = monsterMapper.findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(map);
for (Map<String, Object> monsterMap : monsters) {
//遍历 monsterMap(第一种方法),取出属性和对应的值
//第一种方法
//for (String keys : monsterMap.keySet()) {
// System.out.println("key:"+ keys + " value:" + monsterMap.get(keys));
//}
//System.out.println("--------------------------------------");
//第二种方法
for(Map.Entry<String, Object> entry : monsterMap.entrySet()){
System.out.println(entry.getKey() + "==>" + entry.getValue());
}
System.out.println("--------------------------------------");
}
if(sqlSession != null){
sqlSession.close();
}
System.out.println("操作成功");
}

resultMap(结果集映射)
当实体类的属性和表的字段名字不一致时,我们可以通过 resultMap 进行映射,从而屏蔽实体类属性名和表的字段名的不同。
应用实例
创建表 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
创建 User.java
package com.lzw.entity;
/**
* @author LiAng
*/
public class User {
private Integer user_id;
private String username;
private String useremail;
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUseremail() {
return useremail;
}
public void setUseremail(String useremail) {
this.useremail = useremail;
}
@Override
public String toString() {
return "User{" +
"user_id=" + user_id +
", username='" + username + '\'' +
", useremail='" + useremail + '\'' +
'}';
}
}
创建 UserMapper.java
package com.lzw.mapper;
import com.lzw.entity.User;
import java.util.List;
/**
* @author LiAng
*/
public interface UserMapper {
//添加方法
public void addUser(User user);
//查询所有的User
public List<User> findAllUser();
}
创建 UserMapper.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.lzw.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>
</mapper>
创建 UserMapperTest.java
package com.lzw.mapper;
import com.lzw.entity.User;
import com.lzw.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
/**
* @author LiAng
*/
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@qq.com");
userMapper.addUser(user);
if(sqlSession != null){
sqlSession.commit();
sqlSession.close();
}
System.out.println("操作成功");
}
}

修改 UserMapper.xml
<!--
1. 配置方法public List<User> findAllUser();
2. 返回所有的user信息
3. 按照传统的方式完成,会出现什么问题?=> 如果对象属性名和表字段相同时,就会设置值, 如果不同, 就会是默认值
-->
<select id="findAllUser" resultType="User">
select * from `User`
</select>
修改 UserMapperTest.java
@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("操作成功");
}

修改 UserMapper.xml
<!--
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>
- 如果是 MyBatis-Plus 处理就比较简单,可以使用注解@TableField 来解决 实体字段名和表字段名不一致的问题,还可以使用@TableName 来解决 实体类名和表名不一致的问题。