# 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 星期一 事件描述备注:保存/发布 [](如果不需要此记录可以手动删除,每次保存都会自动的追加记录)