持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
MyBatis获取参数值的两种方式: ${} 和 #{}
${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引
号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,
可以自动添加单引号
推荐使用#{},避免SQL注入
mapper接口的方法(可能有参数,毕竟是方法)直接对应的是映射文件的SQL语句。我们现在要做的就是在映射文件中,通过指定的方式来获取对应的方法的参数,然后拼接到SQL语句中。这就是本章节的目的。
1.单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型
此时可以使用{}和#{}以任意的名称获取参数的值,注意{}需要手动加单引号
字面量和变量是相对应的,如 int a= 1;这里1是字面量,你看到的是什么就是什么,变量a具体值要看字面量。
字符串,基本数据类型以及所对应的包装类都是字面量。
mapper接口
public interface UserMapper {
//根据用户名查询用户信息
User getUserByUsername(String username);
}
映射文件
当你写完**select * from t_user where username =**时,你会发现后面不知道怎么写,你可以试着在等于号后面写上#{username},你会发现其实可以运行了。
如果你把#{username}改成#{abc},你会发现程序居然可以运行,所以可知mybatis底层代码它参数值时,并不知道你是用username还是abc还赋值的。我们知道这件事后,建议还是不要用这么随意的名字,你mapper接口方法参数是username,你映射文件还是用#{username},见名知意最好。
用{}带来的值当成数据库字段,从而程序报错。你不加单引号就会select * from t_user where username = admin,你加了单引号就会select * from t_user where username = 'admin'
<?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.atguigu.mybatis.mapper.UserMapper">
<!--User getUserByUsername(String username)-->
<select id="getUserByUsername" resultType="User">
<!--select * from t_user where username = #{abc}-->
select * from t_user where username = #{username}
<!--select * from t_user where username = '${username}'-->
</select>
</mapper>
测试类(记得复制以前生成sqlsession对象的工具类)
public class ParameterTest {
@Test
public void testGetUserByUsername() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserByUsername("admin");
System.out.println(user);
}
}
2.多个字面量类型的参数
mapper接口
public interface UserMapper {
//验证登录
User checkLogin(String username,String password);
}
映射文件
这里和第一个例子不同的地方在于,现在有两个参数,你可以先试着这样写select * from t_user where username = #{user} and password = #{password} ,然后会报错。Mybatis会告诉你多个参数时,正确的写法如下:
Available parameters are [arg1, arg0, param1, param2]
原因是多个参数时,Mybatis会将参数放在map集合,以两种方式存储数据
1.以arg0,arg1,arg2...为键,以参数为值
2.以param1,param2,param3...为键,以参数为值
因此,只需通过#{}和${}访问map集合的键,就可以获取相对应的值。
在本例的mapper接口中方法为User checkLogin(String username,String password),所以param1和arg0这两个键的值为username保存的值,param2和arg1这两个键的值为password保存的值。至于你想用param或者arg来作为键,随便你。
<?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.atguigu.mybatis.mapper.UserMapper">
<!--User checkLogin(String username,String password)-->
<select id="checkLogin" resultType="User">
<!--select * from t_user where username = #{user} and password = #{password} 参数错误写法-->
<!--select * from t_user where username = #{arg0} and password = #{arg1}-->
select * from t_user where username = #{param1} and password = #{param2}
<!--select * from t_user where username = '${param1}' and password = '${param2}'-->
</select>
</mapper>
测试类
@Test
public void testcheckLogin() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.checkLogin("admin","123456");
System.out.println(user);
}
3.map集合类型的参数
上面的例子我们知道,多个参数的时候,mybatis会把它们放到一个map集合。
那我们可以自己定义map集合吗? 可以的,自己定义了map集合后,映射文件里面就不用写arg0或者param1之类的mybatis提供的键名,而是用我们自己定义的键名。
mapper接口
public interface UserMapper {
//验证登录
User checkLogin(String username,String password);
//验证登录(用map集合作为参数)
User checkLoginByMap(Map<String,Object> map);
}
映射文件
<!--User checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
测试类
@Test
public void testCheckLoginByMap() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<>();
map.put("username","admin");
map.put("password","123456");
User user = mapper.checkLoginByMap(map);
System.out.println(user);
}
4.实体类型的参数
这部分的目的是,怎么将实体类里面的各个属性的值拼接到SQL语句里面。
若mapper接口中的方法参数为实体类对象时
此时可以使用{}和#{},通过访问实体类对象中的**属性名**获取属性值,注意{}需要手动加单引号
注意:属性名和成员变量没有关系,只跟get和set有关系,把get和set去掉,其余部分首字母变小写的结果就是属性名,如getUsername(),去掉get,U变u,得到username,username就是属性名
mapper接口
public interface UserMapper {
//添加用户信息
void insertUser(User user);
}
映射文件
<!--void insertUser(User user);-->
<insert id="insertUser">
insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})
</insert>
测试类
public void testInsertUser() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(null,"root","123456",33,"女","123@qq.com");
mapper.insertUser(user);
}
5.使用@Param标识的参数
可以通过 @Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以两种方式存储
1.@Param注解的value属性值为键,以参数为值;
2.param1,param2...为键,以参数为值;
只需要通过${}和#{}访问map集合的键就可以获取相对应的值,
注意${}需要手动加单引号
mapper接口
//验证登录(使用@Param)
User checkLoginByParam(@Param("username") String username, @Param("password") String password);
映射文件
<!--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>
测试类
@Test
public void testcheckLoginByParam() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.checkLogin("admin","123456");
System.out.println(user);
}
总结
建议大家分成两种方式来记即可,一种是实体类,一种是单个参数或者多个参数。如果传递的是实体类,那么你就获取实体类属性就行,如果是其他参数类型,你就给它们都标注上@Param注解。