# MyBatis 中的 Mapper 配置文件的参数引用
*开源技术栏*
Mapper 配置文件 中,SQL语句可以使用 #{} ${} 进行变量的引用,这个引用和 Mapper 接口的函数形参息息相关
## 目录
[TOC]

## 介绍
我们知道标题中提到的两种语法代表的就是变量赋值,但是,在占位符的大括号中,变量名应该是什么呢?
说到这里我们就需要了解下MyBatis 中的多种变量的引用方式
## Mapper 中是单个参数
这种情况就是最简单的情况,Mapper接口中只有一个参数,下面就是Mapper接口的代码。
### Mapper接口
```java
package top.lingyuzhao.test.mapper;
import top.lingyuzhao.test.data.User;
/**
* @author zhao
*/
public interface UserMapper {
/**
* 根据id查询用户
*
* @param id 用户id
* @return 指定 id 对应的用户对象
*/
User selectUserById(int id);
}
```
### Mapper配置文件
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 只有一个参数
变量的赋值方法就是 直接在大括号中写上 变量名 变量名需要与 selectUserById 函数中的形参一致-->
<select id="selectUserById" parameterType="java.lang.Integer" resultType="User">
SELECT *
FROM t_user
WHERE id = #{id}
</select>
</mapper>
```
### MAIN 代码
```
package top.lingyuzhao.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import top.lingyuzhao.test.data.User;
import top.lingyuzhao.test.mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
/**
* @author zhao
*/
public class Main {
public static void main(String[] args) throws IOException {
// 获取到核心配置文件
final InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取 sql 会话的工厂构建对象
final SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 开始进行构建 在这里我们将配置文件的数据流传递给它 并调用 openSession 获取到会话对象
final SqlSession sqlSession = sqlSessionFactoryBuilder
.build(resourceAsStream)
// TODO 这里需要传递一个 true 代表打开事务自动提交
.openSession(true);
// 获取到映射器对象 在这里将映射接口传递进去
final UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 查询到 id 为 2 的用户
final User user = mapper.selectUserById(2);
System.out.println(user);
}
}
```
### 运行结果
```
2024-01-02 18:44:50,822 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Preparing: SELECT * FROM t_user WHERE id = ?
2024-01-02 18:44:50,852 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Parameters: 2(Integer)
2024-01-02 18:44:50,867 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - <== Total: 1
User{id=2, username='zhao123', password='0000', age=20, sex=男, email='xxx.@qq.com'}
进程已结束,退出代码0
```
## Mapper 中是多个参数
在这里需要注意下,如果Mapper接口中的函数形参是多个,我们不能直接在大括号写变量名,不用纠结为什么,这是mybatis 的规则,接下来就有如何进行变量的引用。
### Mapper接口
```
package top.lingyuzhao.test.mapper;
import top.lingyuzhao.test.data.User;
/**
* @author zhao
*/
public interface UserMapper {
/**
* 根据id1 或者 id2 查询用户
*
* @param id1 用户id1
* @param id2 用户id2
* @return 指定 id 对应的用户对象
*/
List<User> selectUserById(int id1, int id2);
}
```
### MAIN代码
```
package top.lingyuzhao.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import top.lingyuzhao.test.data.User;
import top.lingyuzhao.test.mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author zhao
*/
public class Main {
public static void main(String[] args) throws IOException {
// 获取到核心配置文件
final InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取 sql 会话的工厂构建对象
final SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 开始进行构建 在这里我们将配置文件的数据流传递给它 并调用 openSession 获取到会话对象
final SqlSession sqlSession = sqlSessionFactoryBuilder
.build(resourceAsStream)
// TODO 这里需要传递一个 true 代表打开事务自动提交
.openSession(true);
// 获取到映射器对象 在这里将映射接口传递进去
final UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 查询到 id 为 1 or 2 的用户
final List<User> user = mapper.selectUserById(1, 2);
System.out.println(user);
}
}
```
### Mapper配置文件
在这里我们先按照 单个参数 的方法来直接赋值看看会发生什么吧!
错误示例
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 函数有两个参数
变量的赋值方法就是 直接在大括号中写上 arg0 或者 arg1
也可以写 param0 或者 param1 都是可以的,这代表的就是函数的形参
0 结尾的是第一个形参,以此类推 -->
<select id="selectUserById" parameterType="java.lang.Integer" resultType="User">
SELECT *
FROM t_user
WHERE id = #{id1} or id = #{id2}
</select>
</mapper>
```
像上面这样配置 Mapper 会报错,报错内容如下所示,它在告知,你需要使用 arg0 arg1 param1 param2 的方法来代表第一个参数和第二个参数,其中,arg0 和 param1 代表函数第一个参数,后面的以此类推。
```
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'id1' not found. Available parameters are [arg1, arg0, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id1' not found. Available parameters are [arg1, arg0, param1, param2]
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:153)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87)
at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
at com.sun.proxy.$Proxy4.selectUserById(Unknown Source)
at top.lingyuzhao.test.Main.main(Main.java:31)
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id1' not found. Available parameters are [arg1, arg0, param1, param2]
at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:45)
at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
at org.apache.ibatis.executor.BaseExecutor.createCacheKey(BaseExecutor.java:219)
at org.apache.ibatis.executor.CachingExecutor.createCacheKey(CachingExecutor.java:146)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:88)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
... 8 more
```
### 正确示例
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 函数有两个参数
变量的赋值方法就是 直接在大括号中写上 arg0 或者 arg1
也可以写 param0 或者 param1 都是可以的,这代表的就是函数的形参
0 结尾的是第一个形参,以此类推 -->
<select id="selectUserById" parameterType="java.lang.Integer" resultType="User">
SELECT *
FROM t_user
WHERE id = #{param1} or id = #{param2}
</select>
</mapper>
```
### 运行结果
下面就是运行结果,有关 MAIN 的代码可以在本节中的 Mapper接口 中查阅。
```
2024-01-02 18:55:00,352 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Preparing: SELECT * FROM t_user WHERE id = ? or id = ?
2024-01-02 18:55:00,376 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Parameters: 1(Integer), 2(Integer)
2024-01-02 18:55:00,397 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - <== Total: 2
[User{id=1, username='zhao', password='0000', age=21, sex=男, email='xxx.@qq.com'}, User{id=2, username='zhao123', password='0000', age=20, sex=男, email='xxx.@qq.com'}]
进程已结束,退出代码0
```
## Mapper 中是一个 Map 集合
这其实就是一种多参数接收的变体,这样的方式可以实现参数名字的自定义,我们知道在上一节中,参数的名字都是 arg 以及 param 这两个 mybatis 中写死的名字,我们要是希望自定义参数名字 可以在这里学习到。
本质就是 Map 中的 key 就是变量名字 value 就是变量的具体数值,接下来开始学习。
### Mapper接口
在这的形参变为了一个 Map 对象,下面就是 Mapper 接口的code。
```
package top.lingyuzhao.test.mapper;
import top.lingyuzhao.test.data.User;
import java.util.List;
import java.util.Map;
/**
* @author zhao
*/
public interface UserMapper {
/**
* 根据 id 或者 username 查询用户
* @param map 参数列表 其中 key 是参数名字 value 是参数数值
* @return 指定 id 对应的用户对象
*/
List<User> selectUserById(Map<String, Object> map);
}
```
### Mapper配置文件
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 函数是一个 Map
我们在这里就是读取Map中 key 为 id 以及 username 对应的值
-->
<select id="selectUserById" parameterType="java.util.Map" resultType="User">
SELECT *
FROM t_user
WHERE id = #{id} or username = #{username}
</select>
</mapper>
```
### MAIN 代码
```
package top.lingyuzhao.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import top.lingyuzhao.test.data.User;
import top.lingyuzhao.test.mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
/**
* @author zhao
*/
public class Main {
public static void main(String[] args) throws IOException {
// 获取到核心配置文件
final InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取 sql 会话的工厂构建对象
final SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 开始进行构建 在这里我们将配置文件的数据流传递给它 并调用 openSession 获取到会话对象
final SqlSession sqlSession = sqlSessionFactoryBuilder
.build(resourceAsStream)
// TODO 这里需要传递一个 true 代表打开事务自动提交
.openSession(true);
// 获取到映射器对象 在这里将映射接口传递进去
final UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 准备参数 Map
final HashMap<String, Object> hashMap = new HashMap<>();
// 指定要查询的用户 id
hashMap.put("id", 1);
// 指定要查询的用户名字
hashMap.put("username", "zhao123");
// 开始进行查询
final List<User> user = mapper.selectUserById(hashMap);
System.out.println(user);
}
}
```
### 运行结果
```
2024-01-02 19:06:16,154 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Preparing: SELECT * FROM t_user WHERE id = ? or username = ?
2024-01-02 19:06:16,180 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Parameters: 1(Integer), zhao123(String)
2024-01-02 19:06:16,199 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - <== Total: 2
[User{id=1, username='zhao', password='0000', age=21, sex=男, email='xxx.@qq.com'}, User{id=2, username='zhao123', password='0000', age=20, sex=男, email='xxx.@qq.com'}]
进程已结束,退出代码0
```
## 自定义Mapper中参数的名字
在 Mapper 中是多个参数的时候 参数名字是MyBatis 提供的,如果我们要是希望实现自定义名字,还需要自己构建一个 Map,这比较麻烦,所以我们可以直接使用注解的方式来针对参数进行重命名。
### Mapper 接口
```
package top.lingyuzhao.test.mapper;
import org.apache.ibatis.annotations.Param;
import top.lingyuzhao.test.data.User;
import java.util.List;
/**
* @author zhao
*/
public interface UserMapper {
/**
* 根据id1 或者 id2 查询用户
*
* @param id1 用户id1
* @param id2 用户id2
* @return 指定 id 对应的用户对象
*/
List<User> selectUserById(@Param("id_1") int id1, @Param("id_2") int id2);
}
```
### Mapper配置文件
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 函数有两个参数
分别被我们使用注解命名为了 id_1 id_2 -->
<select id="selectUserById" parameterType="top.lingyuzhao.test.data.User" resultType="User">
SELECT *
FROM t_user
WHERE id = #{id_1}
or id = #{id_2}
</select>
</mapper>
```
### MAIN 代码
```
package top.lingyuzhao.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import top.lingyuzhao.test.data.User;
import top.lingyuzhao.test.mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author zhao
*/
public class Main {
public static void main(String[] args) throws IOException {
// 获取到核心配置文件
final InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取 sql 会话的工厂构建对象
final SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 开始进行构建 在这里我们将配置文件的数据流传递给它 并调用 openSession 获取到会话对象
final SqlSession sqlSession = sqlSessionFactoryBuilder
.build(resourceAsStream)
// TODO 这里需要传递一个 true 代表打开事务自动提交
.openSession(true);
// 获取到映射器对象 在这里将映射接口传递进去
final UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 开始进行查询
final List<User> user = mapper.selectUserById(1, 2);
System.out.println(user);
}
}
```
### 运行结果
```
2024-01-02 19:23:34,084 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Preparing: SELECT * FROM t_user WHERE id = ? or id = ?
2024-01-02 19:23:34,100 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Parameters: 1(Integer), 2(Integer)
2024-01-02 19:23:34,115 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - <== Total: 2
[User{id=1, username='zhao', password='0000', age=21, sex=男, email='xxx.@qq.com'}, User{id=2, username='zhao123', password='0000', age=20, sex=男, email='xxx.@qq.com'}]
进程已结束,退出代码0
```
## Mapper 中是一个 实体类
在 myBatis 中 我们的Mapper接口也可以是一个实体类,这个就是很常用的一种手段,所以我们先来创建一个存储数据的实体类。
### 创建实体类型
```
package top.lingyuzhao.test.data;
/**
* @author zhao
*/
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private Character sex;
private String email;
public User(Integer id, String username, String password, Integer age, Character sex, String email) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex=" + sex +
", email='" + email + '\'' +
'}';
}
}
```
### Mapper接口
```
package top.lingyuzhao.test.mapper;
import top.lingyuzhao.test.data.User;
import java.util.List;
/**
* @author zhao
*/
public interface UserMapper {
/**
* 根据 id 或者 username 查询用户
* @param user 用户数据参数 其中具有 id 和 username 字段
* @return 指定 id 对应的用户对象
*/
List<User> selectUserById(User user);
}
```
### Mapper配置文件
```
<?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 接口 -->
<mapper namespace="top.lingyuzhao.test.mapper.UserMapper">
<!--
函数名称为 selectUserById
参数类型为 整形 代表要查询的数据的 id
返回值是一个 User 对象
TODO 这个 selectUserById 函数形参是一个 User 对象
我们在这里就是读取 User 中 属性 为 id 以及 username 对应的值
-->
<select id="selectUserById" parameterType="top.lingyuzhao.test.data.User" resultType="User">
SELECT *
FROM t_user
WHERE id = #{id}
or username = #{username}
</select>
</mapper>
```
### MAIN 代码
```
package top.lingyuzhao.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import top.lingyuzhao.test.data.User;
import top.lingyuzhao.test.mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author zhao
*/
public class Main {
public static void main(String[] args) throws IOException {
// 获取到核心配置文件
final InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取 sql 会话的工厂构建对象
final SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 开始进行构建 在这里我们将配置文件的数据流传递给它 并调用 openSession 获取到会话对象
final SqlSession sqlSession = sqlSessionFactoryBuilder
.build(resourceAsStream)
// TODO 这里需要传递一个 true 代表打开事务自动提交
.openSession(true);
// 获取到映射器对象 在这里将映射接口传递进去
final UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 准备参数
final User userObj = new User(
// 指定要查询的用户 id
1,
// 指定要查询的用户名字
"zhao123",
// 其它参数用不上
null, null, null, null
);
// 开始进行查询
final List<User> user = mapper.selectUserById(userObj);
System.out.println(user);
}
}
```
### 运行结果
```
2024-01-02 19:17:02,743 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Preparing: SELECT * FROM t_user WHERE id = ? or username = ?
2024-01-02 19:17:02,766 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - ==> Parameters: 1(Integer), zhao123(String)
2024-01-02 19:17:02,782 [main] DEBUG [top.lingyuzhao.test.mapper.UserMapper.selectUserById] - <== Total: 2
[User{id=1, username='zhao', password='0000', age=21, sex=男, email='xxx.@qq.com'}, User{id=2, username='zhao123', password='0000', age=20, sex=男, email='xxx.@qq.com'}]
进程已结束,退出代码0
```
------
***操作记录***
作者:[root](http://www.lingyuzhao.top//index.html?search=1 "root")
操作时间:2024-01-08 08:54:20 星期一
事件描述备注:保存/发布
[](如果不需要此记录可以手动删除,每次保存都会自动的追加记录)
------
***操作记录***
作者:[root](http://www.lingyuzhao.top//index.html?search=1 "root")
操作时间:2024-01-08 08:55:47 星期一
事件描述备注:保存/发布
[](如果不需要此记录可以手动删除,每次保存都会自动的追加记录)