本文已参与「新人创作礼」活动,一起开启掘金创作之路。
mapper.xml的SQL语句中的占位符${}和#{}
一般会采用#{},#{}在mybatis中,最后会被解析为?,其实就是Jdbc的PreparedStatement中的?占位符,它有预编译的过程,会对输入参数进行类型解析(如果入参是String类型,设置参数时会自动加上引号),可以防止SQL注入,如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String),#{}中的变量名可以任意,如果入参类型是pojo,比如是Student类
public class Student{
private String name;
private Integer age;
//setter/getter
}
那么#{name}表示取入参对象 Student 中的 name 属性,#{age}表示取age属性,这个过程是通过反射来做的,这不同于${},${}取对象的属性使用的是 OGNL(Object Graph Navigation Language) 表达式
而${},一般会用在模糊查询的情景,比如SELECT * FROM student WHERE name like '%${name}%';
它的处理阶段在#{}之前,它不会做参数类型解析,而仅仅是做了字符串的拼接,若入参的 Student 对象的name属性为zhangsan,则上面那条 SQL 最终被解析为SELECT * FROM student WHERE name like '%zhangsan%';
而如果此时用的是SELECT * FROM student WHERE name like '%#{name}%'; 这条 SQ L最终就会变成
SELECT * FROM student WHERE name like '%'zhangsan'%'; 所以模糊查询只能用${},虽然普通的入参也可以用${},但由于${}不会做类型解析,就存在 SQL注入 的风险,比如
SELECT * FROM user WHERE name = '${name}' AND password = '${password}'
我可以让一个user对象的password属性为'OR '1' = '1,最终的 SQL 就变成了
SELECT * FROM user WHERE name = 'yogurt' AND password = ''OR '1' = '1',因为OR '1' = '1'恒成立,这样攻击者在不需要知道用户名和密码的情况下,也能够完成登录验证
另外,对于 pojo 的入参,${}中获取对象属性的语法和#{}几乎一样,但${}在 mybatis 底层是通过 OGNL 表达式语言进行处理的,这跟#{}的反射处理有所不同
对于简单类型(8种java原始类型再加一个String)的入参,${}中参数的名字必须是value,例子如下
<select id="fuzzyCount" parameterType="string" resultType="int">
SELECT count(1) FROM `user` WHERE name like '%${value}%'
</select>
结合 Mapper 实现
- 创建 Mapper 接口类;
- 创建 Mapper 的 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.yogurt.mapper.StudentMapper">
<select id="findAll" resultType="com.yogurt.po.Student">
SELECT * FROM student;
</select>
<insert id="insert" parameterType="com.yogurt.po.Student">
INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});
</insert>
<delete id="delete" parameterType="int">
DELETE FROM student WHERE id = #{id};
</delete>
<select id="findByName" parameterType="string" resultType="student">
SELECT * FROM student WHERE name like '%${value}%';
</select>
</mapper>
mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来
- mapper接口的全限定名,要和mapper.xml的namespace属性一致;
- mapper接口中的方法名要和mapper.xml中的SQL标签的id一致;
- mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致;
- mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致;
Mybatis 工具类
- 先 new 一个 SqlSessionFactoryBuilder(),得到一个返回值 builder;
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
- 获取我们的 SqlSessionFactory,要用builder.上我们的 builder() 方法,通过流的形式传一个In的参数;
- 通过 Resources.getResourceAsStream("") 读取我们的主配置文件才能调用我们的依赖信息,在这里抛异常。这里有一个返回值 nputStream in(字节流),通过字节流就可以读取;
- 这时 builder.build(in) ;得到哟个返回值就是 SqlSessionFactory factory;
- 得到 SqlSessionFactory factory 之后,根据图片的流程就要得到我们的 SqlSession;
- factory.openSession() 打开我们的 Session,就可以得到我们的 Session;
- 执行 sql 语句。sqlSession.getMapper(这里的 mapper 利用的是我们的一个反射机制,机制利用的时我们的一个接口)通过 sqlSession.getMapper(PersonMapper.class) 调用一个调用方法,得到一个返回值 count;
- 输出对应的返回值;
- 关闭 sqlsession;
关于 Mybatis 就通过这两篇博客介绍完毕了,答辩现场反正也没多长时间介绍,把自己知道的都说出来就好。
有错误请指正
我向你敬礼啊,Salute!