前提提要
- 本系列Mybatis笔记基于mybatis3.5.2 , https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.2中有详细的文档说明,可以进行下载阅读,本文只是对Mybatis的一些常用操作进行汇总总结。
- 推荐视频资料:https://www.bilibili.com/video/BV1VP4y1c7j7?p=1
- 所需前提:对maven有些了解。(maven v3.6.1)如果对maven不是很熟悉推荐博主文章。Maven常用知识梳理总结
- MyBatis系列文章索引页✋
- IDE: IntelliJ IDEA 2021.3
- 构建工具: apache-maven-3.6.3
- MySQL版本:MySQL 5.7.35
- MyBatis版本:MyBatis 3.5.7
对于mybatis
框架的使用,按照上次介绍的,我们配置的映射文件中,通过namespace
将映射文件和接口关联起来了。
具体方法通过id
精确的对应。然后,方法对应的具体数据操作,在mapper
文件中的<insert><select>....
书写具体的SQL语句来进行实现。
但是,对于一些需要传输数据的行为,如条件查询,插入操作等等,都需要将用户调用接口的实际参数数据,落实到具体的mapper
文件中的各个方法中。
问题来了?
给接口的实际参数,mapper
实际操作如何取对应的数据, 数据是以什么方式传递给mapper
中各标签实现数据的CRUD
操作的呢?
文章目录
一,IDEA中设置各种配置文件的模板🍍
这节内容主要就是平时开发过程中的技巧性操作。
1. 设置mybatis-config.xml文件模板
模板内容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"></properties>
<typeAliases>
<package name=""></package>
</typeAliases>
<!--设置连接数据库的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url"
value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<package name=""/>
</mappers>
</configuration>
在IDEA
中添加mybatis-config.xml
文件模板的具体操作:
最后的效果如图所示,新建完上述模板之后,就可以按照上述你创建的模板创建一个mybatis-config.xml
文件。
2. 设置 **mapper.xml映射文件模板🖼
和上述mybatis-confg.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="">
</mapper>
具体的操作和设置mybatis-config.xml
操作是一样的。
二,获取参数的两种方式🍋
✍在谈将调用接口的实际参数传给mapper
中各个标签实际操作是什么样之前,我们先看看mapper
中获取参数的两种方式,我们知道JDBC
中有两种设置参数的方式:
- 通过参数预处理的方式 2. 通过拼接SQL的方式
@Test
public void testJDBC() throws SQLException, ClassNotFoundException {
String username = "cherry";
Class.forName("");
Connection connection = DriverManager.getConnection("", "", "");
// 1. 字符串拼接 ->获得预编译对象 -》sql注入问题
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_user where username = '" + username + "'");
// 2. 占位符
PreparedStatement ps2 = connection.prepareStatement("select * from t_user where username = ?");
ps2.setString(1, username);
}
对应于MyBatis
中,我们也有这两种方式:1. 字符串拼接 2. 占位符
🎾MyBatis获取参数值的两种方式:${}
和#{}
,就和JDBC
中的两种方式一脉相承。
${}
的本质就是字符串拼接#{}
的本质就是占位符赋值
${}
使用字符串拼接的方式拼接sql
,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}
使用占位符赋值的方式拼接sql
,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号(尽量使用这一种)。🤬
两种方式的具体区别可以查看博主的另外一篇文章:
Mybatis参数绑定中的#{ }和${ }区别剖析
三,MyBatis获取参数值的五种情况🚐
通过了上述说明了Mybatis
中两种获取基本方式的区别。下面通过给接口
床传递实参不同的形式来划分为一下五种情况进行一一的说明。
3.1 单个字面量类型的参数
也就是如果调用的形式是:
getUserById(1)
🏟若mapper
接口中的方法参数为单个的字面量类。此时可以使用${}
和#{}
以任意的名称获取参数的值,注意${}
需要手动加单引号。
如下所示:
public interface ParameterMapper {
/**
* 单个的字面量类型:
* 根据用户名查询用户信息
*/
User getUserByUserName(String username);
}
在对应的配置类中进行配置,按照上述的方式,都可以进行配置,如下:
🆘Notice:使用#{}
,里面内容可以随便写,都是传进来的username
的值。
方式一:
<!-- User getUserByUserName(String username);-->
<!-- 使用#{},里面内容可以随便写,都是传进来的username的值-->
<select id="getUserByUserName" resultType="User">
select * from t_user where username = #{username}
</select>
方式二:
<!-- User getUserByUserName(String username);-->
<select id="getUserByUserName" resultType="User">
<!--
select * from t_user where username = ${username}
如果使用这种方式,得到的sql语句是:
Preparing: select * from t_user where username = RUOYI
而其中username的值‘RUOYI’没有单引号,语句不正确,会报错。
因此要手动添加单引号
-->
select * from t_user where username = '${username}'
</select>
测试类:
/**
* MyBatis获取参数值的各种情况:
* 情况1: mapper接口方法的参数为单个字面量的参数
* 可以通过${} #{}以任意的字符串获得参数值,但需要注意${}的单引号问题
*/
@Test
public void testgetUserByUserName(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.getUserByUserName("");
System.out.println(user);
}
3.2 多个字面量类型的参数
若在mapper
接口的方法中有多个参数的时候,我们MyBatis
的操作是会自动的将这些参数放到一个Map
集合中。通过以arg0, arg1, arg2... argn
,以参数值为值。还有一种就是通过param1, param2...
,以参数为值。
📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧
因此,只要通过#{}
或者是${}
访问map
集合中的键就可以获取到对应的值。但是需要注意的是${}
需要手动加上单引号。
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLogin(String username, String password);
}
对应在mapper
映射文件中:
<!-- User checkLogin(String username, String password);-->
<select id="checkLogin" resultType="User">
<!--
写:select * from t_user where username = #{username} and password = #{password}
会报错:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
因为sql语句没有解析成功-->
<!--以map集合形式存储,arg0->param0, arg1->param1,这时直接用键arg访问就好了,用param访问也行。
以下两种方式选一个:-->
select * from t_user where username = #{arg0} and password = #{arg1}
select * from t_user where username = '${param1}' and password = '${param2}'
</select>
测试类:
/**
* 情况2:mapper接口方法的参数为多个时
* 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
* a》以arg0,arg1。。为键,参数为值
* b》以param0,param1。。为键,参数位置
* 因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题
*/
@Test
public void testCheckLogin(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.checkLogin("fangshaolei","123456");
System.out.println(user);
}
Notice: 写:select * from t_user where username = #{username} and password = #{password}
会报错:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
因为sql
语句没有解析成功
3.3 Map集合类型的参数
我们大概有了一些思路,基本上对于所有的参数。Mybatis
的操作都是先将所有的参数都封装到一个map
中,然后在mapper
中使用#{}
或者是${}
来进行取。
如果mapper
接口中的方法需要的参数为多个时,此时可以手动创建map集合,也就是我们不在通过mybatis
来进行创建参数,而是手动的自己传过去一个map
。
🌼所以,将这些数据放在map
中只需要通过${}
和#{}
访问map
集合的键就可以获取相对应的值,注意${}
需要手动加单引号.
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLoginByMap(Map<String, Object> map);
}
在对应的map
中进行取用的操作。
<!-- User checkLoginByMap(Map<String, Object> map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
测试类:
/**
* 情况3:若mapper接口方法的参数有多个时,可以手动将这些参数放在一个map中存储
* 只需要通过#{} ${}以键的方式访问值即可,但是需要注意${}的单引号问题
*/
@Test
public void testCheckLoginByMap(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("username","RUOYI");
map.put("password","123456");
User user = mapper.checkLoginByMap(map);
System.out.println(user);
}
🆘Notice:但是需要注意的是,对于自己封装的map
的形式,在使用两种方式进行取用的时候,需要指定在map
中的键,也就是我们自己存在map
数据中的键。
3.4 实体类参数
🚦如果mapper
接口中的方法参数是实体类对象的时候,此时可以使用 #{}
和${}
,通过访问实体类对象中的属性名获取属性值,同样需要注意的是:${}
需要手动加上单引号。
其实,实体类对象参数,在mybatis
中会被封装成map
对象的形式。
Mapper
对应的接口:
public interface ParameterMapper {
/**
* 添加用户信息
*/
int insertUser(User user);
}
Mapper.xml
文件中的配置:
<!-- int insertUser(User user);-->
<!-- 找到相对应的get方法,如username->找getUsername(),看get/set方法-->
<insert id="insertUser">
insert into t_user values(null, #{username}, #{password}, #{age}, #{gender}, #{email})
</insert>
测试类:
/**
* 情况4:mapper接口方法的参数是实体类类型的参数(web从control层传过来的)
* 只需要通过#{} ${}以属性的方式访问属性值即可,但是需要注意${}的单引号问题
*/
@Test
public void testInsertUser(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = new User(null, "fangshaolei", "123456", 66, "m", "sl.fang@gmail.com");
mapper.insertUser(user);
}
Notice:同样需要注意的是,#{}
中的参数名称不能随意的写,要和属性名称一致。
3.5 使用@Param标识参数
🚿通过上述的四种方法,我们知道,除了只有一个字面量参数之外。其他的参数通过#{}
或者是${}
取用的值都需要正确的给定Mybatis
内部map
的键。
如果是多个字面量,按照Mybatis
内部默认的键来进行取用。如果传过来的参数是自己定义的Map
或者是实体类对象
的形式。则在取用的时候,指定参数名称和自定义Map
的键一致和如果参数是实体类对象,则需要和对象的属性名一致。
😵
但是,我们能够自定义Mybatis
内部已经封装好的Map
的key
,从而通过#{}
或者是${}
的形式,利用我们自定义的key
来进行取用呢?
这就需要通过@Param
来实现。
🚣♂️可以通过@Param
注解标识mapper
接口中的方法参数。此时,会将这些参数放在map
集合中,以@Param
注解的value
属性值为键,以参数为值;
以 param1,param2...
为键,以参数为值;
只需要通过${}
和#{}
访问map
集合的键就可以获取相对应的值, 注意${}
需要手动加单引号。
public interface ParameterMapper {
/**
* 验证登录 (使用@Param)
*/
User checkLoginByParam(@Param("username") String username, @Param("password") String password);
}
对应的mapper.xml
配置:
<!-- 以@Param的值为键,参数为值; 或以"param1"/"param2"为键,参数为值-->
<!-- User checkLoginByParam(@Param("username") String username, @Param("password") String password);-->
<select id="checkLoginByParam" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
测试类:
/**
* 情况5:使用@Param注解来命名参数
* 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
* a》以@Param的值为键,参数为值; @Param(value = "xxx")
* b》以param0,param1...为键,参数为值
*/
@Test
public void testCheckLoginByParam(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.checkLoginByParam("fangshaolei","123456");
System.out.println(user);
}
而对于参数传递的源码分析,可以看博主的另外一篇博文:👩🏫
四,总结🌼
我们还是把第一篇博文的图片拿出来分析:
🥪我们知道,对于参数传递的总体位置是在:在mybatis
中是如何将给接口的参数
,被mapper.xml
进行接收的。
博文中,分开了五种情况来进行介绍。
🎦对于上述的几种情况:对于开发中,我们常用的思路就是,无论你是单字面量还是多字面量。无论是对象,还是map
。
我们一律通过两种方式来使用:
- 所有的非实体类,非
map
。我们都打上一个@Param
来指定取用的参数名称。 - 如果是实体类和
map
,则直接使用key
或者是对象的属性名。
所以,我们只需要记住两种情况就可以。
推荐阅读 | 参考博文
https://blog.csdn.net/bdqx_007/article/details/94836637
https://www.cnblogs.com/mingyue1818/p/3714162.html
https://baijiahao.baidu.com/s?id=1695300185179901379&wfr=spider&for=pc
https://blog.51cto.com/legend2011/1030804
🌈🌈🌈文章还有许多不足的地方,欢迎指正。💌