文章目录
视频链接:https://www.bilibili.com/video/BV1VP4y1c7j7?p=22&spm_id_from=pageDriver
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>
添加模版步骤
创建模版
完成后就可以直接new一个mybatis-config
模版啦。
2、设置xxxMapper.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>
过程与config模版相同。
3、获取参数值
3.1 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);
}
3.2 MyBatis获取参数值的两种方式
MyBatis获取参数值的两种方式:${}和#{}
- ${}的本质就是字符串拼接
- #{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号(尽量使用这一种)。
3.3 MyBatis获取参数值的五种情况
情况1: 单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型
此时可以使用${}和#{}
以任意的名称获取参数的值,注意${}
需要手动加单引号
ParameterMapper接口:
public interface ParameterMapper {
/**
* 单个的字面量类型:
* 根据用户名查询用户信息
*/
User getUserByUserName(String username);
}
对应在ParameterMapper.xml中配置。
方式一:
<!-- 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("RUOYI");
System.out.println(user);
}
情况2:多个字面量类型的参数
若mapper接口中的方法参数为多个时
此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;
以 param1,param2…为键,以参数为值;
因此只需要通过${}和#{}
访问map集合的键就可以获取相对应的 值,注意${}需要手动加单引号
ParameterMapper接口:
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLogin(String username, String password);
}
对应在ParameterMapper.xml中配置。
<!-- 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->param1, arg1->param2,这时直接用键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("RUOYI","123456");
System.out.println(user);
}
情况3:map集合类型的参数
若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中
只需要通过${}和#{}
访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号
ParameterMapper接口:
public interface ParameterMapper {
/**
* 验证登录
*/
User checkLoginByMap(Map<String, Object> map);
}
对应在ParameterMapper.xml中配置。
<!-- 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);
}
情况实体类类型的参数
若mapper接口中的方法参数为实体类对象时 此时可以使用${}和#{}
,通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号
ParameterMapper接口:
public interface ParameterMapper {
/**
* 添加用户信息
*/
int insertUser(User user);
}
对应在ParameterMapper.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, "Pandora", "4444", 66, "m", "1111@gmail.com");
mapper.insertUser(user);
}
情况5: 使用@Param标识参数
可以通过@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param
注解的value属性值为键,以参数为值;
以 param1,param2...
为键,以参数为值;
只需要通过${}和#{}
访问map集合的键就可以获取相对应的值, 注意${}需要手动加单引号
ParameterMapper接口:
public interface ParameterMapper {
/**
* 验证登录 (使用@Param)
*/
User checkLoginByParam(@Param("username") String username, @Param("password") String password);
}
对应在ParameterMapper.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("RUOYI","123456");
System.out.println(user);
}
4、@Param源码分析
sql语句的唯一标识 command name00
分析代码
目的:验证@Param存储参数的两种方式
/**
* 情况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("RUOYI","123456");
System.out.println(user);
}
(1)打断点,进入debug模式
选择step into进行调试
(2)Mapper底层使用代理模式创建,我们按step into进入缓存cachedInvoker
的invoke()
方法
(3)进入了invoke()
,再进一步进入了mapperMethod
的execute()
方法(step into)。
execute()
方法中包含一个switch语句,分别对应增删改查等关键字对应的处理流程。
(4)点击step over跳进switch语句内部,光标放在command上,点击加号,查看command内容。name为该sql语句的唯一标识,type为对应操作,即SELECT。
再点击step into,发现convertArgsToSqlCommandParam()
方法是由paramNameResolver
参数名称解析器中的getNamedParams()
获取命名参数方法解析的,进一步step into进这个方法。
(5)进入getNamedParams()
方法,查看names,发现names是一个map集合,包含了传进来的"username"、"password"
参数。
由结果再翻上去看@Param
的解析过程。
(6)回到getNamedParams()
方法,继续step over
两次循环entrySet后,发现param集合中得到两种映射
- 以
@Param的value
作为key,参数值为value - 以
param1, param2...
作为key,参数值为value
至此,@Param源码分析完毕,印证结论:可以使用#{param1}
和#{username}
两种方式获得参数值。