对于mybatis
框架的使用,按照上次介绍的,我们配置的映射文件中,通过namespace
将映射文件和接口关联起来了。
具体方法通过id
精确的对应。然后,方法对应的具体数据操作,在mapper
文件中的
书写具体的SQL语句来进行实现。
但是,对于一些需要传输数据的行为,如条件查询,插入操作等等,都需要将用户调用接口的实际参数数据,落实到具体的mapper
文件中的各个方法中。
问题来了?
给接口的实际参数,mapper
实际操作如何取对应的数据, 数据是以什么方式传递给mapper
中各标签实现数据的CRUD
操作的呢?
这节内容主要就是平时开发过程中的技巧性操作。
模板内容:
<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
文件。
和上述mybatis-confg.xml
设置文件模板一样,
模板内容如下:
<mapper namespace="">
mapper>
具体的操作和设置mybatis-config.xml
操作是一样的。
✍在谈将调用接口的实际参数传给mapper
中各个标签实际操作是什么样之前,我们先看看mapper
中获取参数的两种方式,我们知道JDBC
中有两种设置参数的方式:
@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
中两种获取基本方式的区别。下面通过给接口
床传递实参不同的形式来划分为一下五种情况进行一一的说明。
也就是如果调用的形式是:
getUserById(1)
若mapper
接口中的方法参数为单个的字面量类。此时可以使用${}
和#{}
以任意的名称获取参数的值,注意${}
需要手动加单引号。
如下所示:
public interface ParameterMapper {
/**
* 单个的字面量类型:
* 根据用户名查询用户信息
*/
User getUserByUserName(String username);
}
在对应的配置类中进行配置,按照上述的方式,都可以进行配置,如下:
Notice:使用#{}
,里面内容可以随便写,都是传进来的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);
}
若在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
语句没有解析成功
我们大概有了一些思路,基本上对于所有的参数。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
数据中的键。
如果mapper
接口中的方法参数是实体类对象的时候,此时可以使用#{}
和${}
,通过访问实体类对象中的属性名获取属性值,同样需要注意的是:${}
需要手动加上单引号。
其实,实体类对象参数,在mybatis
中会被封装成map
对象的形式。
Mapper
对应的接口:
public interface ParameterMapper {
/**
* 添加用户信息
*/
int insertUser(User user);
}
Mapper.xml
文件中的配置:
<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", "[email protected]");
mapper.insertUser(user);
}
Notice:同样需要注意的是,#{}
中的参数名称不能随意的写,要和属性名称一致。
通过上述的四种方法,我们知道,除了只有一个字面量参数之外。其他的参数通过#{}
或者是${}
取用的值都需要正确的给定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
配置:
<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参数传递介绍与源码分析
我们知道,对于参数传递的总体位置是在:在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
文章还有许多不足的地方,欢迎指正。