文章目录
- 1、回顾JDBC原生的获取参数值的方式
- 2、MyBatis获取参数值的两种方式
- 3、MyBatis获取参数值的五种情况
- 情况1: Mapper接口方法的参数为单个字面量类型的参数
- ParameterMapper接口代码
- 测试类代码
- ParameterMapper.xml配置方式1:```${}```
- ParameterMapper.xml配置方式2:```#{}```
- 情况2:Mapper接口方法的参数有多个,利用Mabatis的map参数集合
- ParameterMapper接口
- 测试类代码
- ParameterMapper.xml错误写法
- ParameterMapper.xml正确写法
- 情况3:Mapper接口方法的参数有多个,利用手动创建的map参数集合
- ParameterMapper接口
- 测试类代码
- ParameterMapper.xml写法1
- ParameterMapper.xml写法2
- 情况4:Mapper接口方法的参数是一个实体类对象【==用的最多的情况之一==】
- ParameterMapper接口
- 测试类代码
- ParameterMapper.xml写法
- 情况5:使用@Param注解来命名参数【很常用的情况】
- ParameterMapper接口
- 测试类代码
- ParameterMapper.xml写法
- 4、建议将5种情况整合为两种情况
- 5、@Param源码分析
1、回顾JDBC原生的获取参数值的方式
- 字符串拼接
- 占位符拼接
@Test
public void testJDBC() throws SQLException, ClassNotFoundException {
String username = "rqs";
Class.forName("");
Connection connection = DriverManager.getConnection("", "", "");
// 1. 字符串拼接 ->获得预编译对象 -》sql注入问题
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_user where username = '" + username + "'");
// 2. 占位符 可以避免sql注入问题
PreparedStatement ps2 = connection.prepareStatement("select * from t_user where username = ?");
ps2.setString(1, username);
}
2、MyBatis获取参数值的两种方式
MyBatis获取参数值的两种方式:${}和#{}
- ${}的本质就是字符串拼接
- #{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,可能会造成sql注入,另外为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
#{}使用占位符赋值的方式拼接sql,不存在sql注入的问题,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号(尽量使用这一种)。
3、MyBatis获取参数值的五种情况
情况1: Mapper接口方法的参数为单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型
此时可以使用${}
和#{}
以任意的名称获取参数的值,注意${}需要手动加单引号
ParameterMapper接口代码
package com.rqs.mybatis.mapper;
import com.rqs.mybatis.pojo.User;
import java.util.List;
public interface ParameterMapper {
/**
* 单个的字面量类型:
* 根据用户名查询用户信息
*/
User getUserByUserName(String username);
}
测试类代码
/**
* MyBatis获取参数值的各种情况:
* 情况1: mapper接口方法的参数为单个字面量的参数
* 可以通过${} #{}以任意的字符串获得参数值,但需要注意${}的单引号问题
*/
@Test
public void testgetUserByUserName(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.getUserByUserName("rqs");
System.out.println(user);
}
ParameterMapper.xml配置方式1:${}
<!-- User getUserByUserName(String username);-->
<select id="getUserByUserName" resultType="User">
<!-- 错误写法:
select * from t_user where username = ${username}
如果使用这种方式,得到的sql语句是:
Preparing: select * from t_user where username = rqs
而其中username的值‘rqs’没有单引号,语法不正确,会报错。
因此要手动添加单引号
-->
select * from t_user where username = '${username}'
</select>
方式1错误写法的结果:
会报错
sql语句的正确写法是:
方式1正确写法的结果:
ParameterMapper.xml配置方式2:#{}
<?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.rqs.mybatis.mapper.ParameterMapper">
<!--User getUserByUserName(String username);-->
<!-- 使用#{},里面内容可以随便写,都是传进来的String username参数的值,该值在测试类中写的mapper.getUserByUserName("rqs"),
所以这里无论怎么写都会获得“rqs”的值,虽然可以随便写,但建议见闻知意思,写传输过来的参数名的名字,此处为username-->
<select id="getUserByUserName" resultType="user">
select * from t_user where username=#{username}
</select>
</mapper>
测试结果:
情况2:Mapper接口方法的参数有多个,利用Mabatis的map参数集合
若mapper接口中的方法参数为多个时
此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;
以 param1,param2…为键,以参数为值;
因此只需要通过${}
和#{}
访问map集合的键就可以获取相对应的 值,注意${}
需要手动加单引号
ParameterMapper接口
package com.rqs.mybatis.mapper;
import com.rqs.mybatis.pojo.User;
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLogin(String username, String password);
}
测试类代码
package com.rqs.mybatis.test;
import com.rqs.mybatis.mapper.ParameterMapper;
import com.rqs.mybatis.pojo.User;
import com.rqs.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class ParameterMapperTest {
/**
* 情况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("rqs","123456");
System.out.println(user);
}
}
ParameterMapper.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="com.rqs.mybatis.mapper.ParameterMapper">
<!-- User checkLogin(String username, String password);-->
<select id="checkLogin" resultType="User">
<!--错误写法-->
<!--会报错:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
因为sql语句没有解析成功-->
select * from t_user where username = #{username} and password = #{password}
</select>
</mapper>
写法1是错的,测试结果:
写法1的报错提示username参数没有找到,当前可用的参数是[arg1,arg0,param1,param2],这是什么意思呢?在MyBatis的底层,如果检测到当前Mapper接口中的方法有多个参数,会自动把这些参数放在一个map集合里,并且以两种方式存储数据,第一种:以arg0,arg1为键,以参数为值,第二种:以param1,param2参数为键,以参数为值。所以,如果要获取map中某一个键所对应的值,直接在#{}
或者${}
里访问map集合的键。本案例中arg0和param1表示的都是User checkLogin(String username, String password);
中的参数username,arg1和param2表示的都是User checkLogin(String username, String password);
中的参数password。即
arg0、param1 -> username
arg1、param2 -> password
ParameterMapper.xml正确写法
任选一种,解释如上黄色部分
键 -> 值关系如下:
arg0、param1 -> username
arg1、param2 -> password
<?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.rqs.mybatis.mapper.ParameterMapper">
<select id="checkLogin" resultType="user">
<!-- User checkLogin(String username, String password);-->
<!--以map集合形式存储,arg0->param1, arg1->param2,这时直接用键arg访问就好了,用param访问也行。
arg0、param1 -> username
arg1、param2 -> password-->
<!--写法2-->
select * from t_user where username = #{arg0} and password = #{arg1}
<!--select * from t_user where username = '${arg0}' and password = '${arg1}' -->
</select>
</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 namespace="com.rqs.mybatis.mapper.ParameterMapper">
<select id="checkLogin" resultType="user">
<!-- User checkLogin(String username, String password);-->
<!--以map集合形式存储,arg0->param1, arg1->param2,这时直接用键arg访问就好了,用param访问也行。
arg0、param1 -> username
arg1、param2 -> password-->
<!--写法3-->
select * from t_user where username = '#{arg0}' and password = '#{param2}'
<!--select * from t_user where username = '${arg0}' and password = '${param2}' -->
</select>
</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 namespace="com.rqs.mybatis.mapper.ParameterMapper">
<select id="checkLogin" resultType="user">
<!-- User checkLogin(String username, String password);-->
<!--以map集合形式存储,arg0->param1, arg1->param2,这时直接用键arg访问就好了,用param访问也行。
arg0、param1 -> username
arg1、param2 -> password-->
<!--写法4-->
select * from t_user where username = '#{param1}' and password = '#{arg1}'
<!--select * from t_user where username = '${param1}' and password = '${arg1}' -->
</select>
</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 namespace="com.rqs.mybatis.mapper.ParameterMapper">
<select id="checkLogin" resultType="user">
<!-- User checkLogin(String username, String password);-->
<!--以map集合形式存储,arg0->param1, arg1->param2,这时直接用键arg访问就好了,用param访问也行。
arg0、param1 -> username
arg1、param2 -> password-->
<!--写法5-->
select * from t_user where username = '#{param1}' and password = '#{arg1}'
<!--select * from t_user where username = '${param1}' and password = '${arg1}' -->
</select>
</mapper>
测试结果均为:
情况3:Mapper接口方法的参数有多个,利用手动创建的map参数集合
Mybatis可以自动将参数放map中,所以若mapper接口中的方法需要的参数为多个时,我们也可以手动创建map集合,将这些数据放在map中,只需要通过${}
和#{}
访问map集合的键就可以获取相对应的值,注意${}
需要手动加单引号
ParameterMapper接口
package com.rqs.mybatis.mapper;
import com.rqs.mybatis.pojo.User;
import java.util.Map;
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLoginByMap(Map<String, Object> map);
}
测试类代码
package com.rqs.mybatis.test;
import com.rqs.mybatis.mapper.ParameterMapper;
import com.rqs.mybatis.pojo.User;
import com.rqs.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class ParameterMapperTest {
/**
* 情况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","rqs");
map.put("password","123456");
User user = mapper.checkLoginByMap(map);
System.out.println(user);
}
}
ParameterMapper.xml写法1
<?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.rqs.mybatis.mapper.ParameterMapper">
<!-- User checkLoginByMap(Map<String, Object> map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
</mapper>
ParameterMapper.xml写法2
<?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.rqs.mybatis.mapper.ParameterMapper">
<!-- User checkLoginByMap(Map<String, Object> map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username = '${username}' and password = '${password}'
</select>
</mapper>
测试结果均为:
情况4:Mapper接口方法的参数是一个实体类对象【用的最多的情况之一】
从浏览器传输过来的是一个完整的表单数据,可以在控制层中获取这些数据并且放在实体类对象中进行存储,这个时候调用service,service调用mappe,传输过来的是一个实体类对象。此时的访问方式类似于map集合,map集合以键进行访问,实体类对象以属性进行访问,注意这里根据属性进行访问主要是看有没有get、set 方法,把get、set方法的方法名中的get和set去掉,把剩下部分的首字母变成小写的结果就是当前的属性名,也就是成员变量,但要注意有一种情况,会出现没有相对应的成员变量却有相对应的get、set方法,此时就不能说没有这个属性了。
ParameterMapper接口
package com.rqs.mybatis.mapper;
import com.rqs.mybatis.pojo.User;
public interface ParameterMapper {
/**
* 添加用户信息
*/
int insertUser(User user);
}
测试类代码
package com.rqs.mybatis.test;
import com.rqs.mybatis.mapper.ParameterMapper;
import com.rqs.mybatis.pojo.User;
import com.rqs.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class ParameterMapperTest {
/**
* 情况4:mapper接口方法的参数是实体类类型的参数(web从control层传过来的)
* 只需要通过#{} ${}以属性的方式访问属性值即可,但是需要注意${}的单引号问题
*/
@Test
public void testCheckLoginByMap(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
int result = mapper.insertUser(new User(null,"lzh","123",23,"男","123@qq.com"));
System.out.println(result);
}
}
ParameterMapper.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="com.rqs.mybatis.mapper.ParameterMapper">
<!-- int insertUser(User user);-->
<!-- 找到相对应的get方法,如username->找getUsername(),看get/set方法-->
<insert id="insertUser">
insert into t_user values(null, #{username}, #{password}, #{age}, #{gender}, #{email})
</insert>
</mapper>
测试结果:
情况5:使用@Param注解来命名参数【很常用的情况】
这种情况适用的场景比较多,是情况2和3的结合。
可以通过@Param注解标识mapper接口中的方法参数,会将这些参数放在map集合中,存储方式有两种。
- 第一种:以@Param注解的value属性值为键,以参数为值;
- 第二种:以 param1,param2…为键,以参数为值;
只需要通过${}
和#{}
访问map集合的键就可以获取相对应的值, 注意${}
需要手动加单引号
ParameterMapper接口
package com.rqs.mybatis.mapper;
import com.rqs.mybatis.pojo.User;
import org.apache.ibatis.annotations.Param;
public interface ParameterMapper {
/**
* 验证登录 (使用@Param)
*/
User checkLoginByParam(@Param("username") String username, @Param("password") String password);
}
测试类代码
package com.rqs.mybatis.test;
import com.rqs.mybatis.mapper.ParameterMapper;
import com.rqs.mybatis.pojo.User;
import com.rqs.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class ParameterMapperTest {
/**
* 情况5:使用@Param注解来命名参数
* 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
* a》以@Param的值为键,参数为值; @Param(value = "xxx")
* b》以param1,param2...为键,参数为值
*/
@Test
public void testCheckLoginByParam(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = mapper.checkLoginByParam("rqs","123456");
System.out.println(user);
}
}
ParameterMapper.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="com.rqs.mybatis.mapper.ParameterMapper">
<!-- 以@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>
</mapper>
测试结果:
4、建议将5种情况整合为两种情况
- 情况1:实体类
- 情况2:@Param
5、@Param源码分析
参考:https://blog.csdn.net/CherryChenieth/article/details/123195302