动态 SQL 是 mybatis 的强大特性之一,mybatis 在对 sql 语句预编译前,会对 sql 进行动态解析,解析为一个 BoundSql 对象,在动态 SQL 解析阶段,#和$的不同:
#可以防止sql注入.先把sql中使用#的地方变成?占位符,再设置参数值
insert into students id = #{id};//id=2
#{}在动态解析后
insert into students id = ?;
再设置参数值,#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号
insert into students id = "2"; //id=2
$会导致sql注入,可以拼接sql
insert into students id = ${id};
在 动 态 解 析 后 , {}在动态解析后, 在动态解析后,将传入的数据直接显示生成在sql中。
insert into students id = 2;//id=2
MyBatis启用了预编译功能,所以防止了sql注入。
MyBatis是如何做到SQL预编译的呢?
我们都知道的,是JDBC中的PreparedStatement类在起作用,PreparedStatement是Statement的子类,使用PreparedStatement不仅能够防止sql注入,而且比Statement提高了效率。
值得一提的是PreparedStatement对#和 $ 都支持,而Statement只支持$.
在Mybaits的6个执行器中BatchExecutor批处理执行类,比较突出,这里就通过它当中的PrepareStatement和Statement来讲原理。
https://blog.csdn.net/qq_37432174/article/details/97567320
1. JDBC中Statement的批处理原理图
对于Statement来说,只要SQL不同,就会产生新编译动作,Statement不支持问号“?”参数占位符。
2.JDBC中PrepareStatement的批处理原理图
对于PrepareStatement,只要SQL相同,就只会编译一次,如果SQL不同呢?此时和Statement一样,会编译多次。PrepareStatement的优势在于支持问号“?”参数占位符,SQL相同,参数不同时,可以减少编译次数至一次,大大提高效率;另外可以防止SQL注入漏洞。
自我理解:
JDBC中Statement和 PrepareStatement的批处理区别:
因为Statement不支持问号“?”参数占位符替换,而PrepareStatement
支持问号“?”参数占位符替换,所以有时候同一sql语句会因为参数的不同而成不同的语句,例如:
insert into students(id) values(1);
insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);
上面的4个Sql,无论是Statement,还是PrepareStatement,对Sql都编译3次。因为其中第1、2条Sql是完全相同的,只会编译1次。
insert into students(id) values(?); // id=[1,2,3]
对于PrepareStatement,支持问号“?”占位符,向数据库中插入id=[1,2,3]三条记录,对Sql只编译1次,由于减少了编译次数,大幅提高了效率。
Statement不支持问号“?”占位符,向数据库中插入id=[1,2,3]三条记录,只能写成下面这样。
insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);
由于Sql不同,所以编译3次,效率较低。
在加入addBatch()前,没有加入参数,语句不会因为参数的不同而显得是不同的sql语句。
只要SQL不同,就会产生新编译动作,
如果是Preparestatement,但是参数可能不同,也是同一条SQL,这样就不需要重复创建PrepareStatement。
如果是Statement,但是参数可能不同,就不是同一条SQL,这样就需要重复创建Statement。
BatchExecutor的批处理原理图
BatchExecutor的批处理,和JDBC的批处理,主要区别就是BatchExecutor维护了一组Statement批处理对象,它有自动路由功能,sqlA、sqlB、sqlC代表不同的SQL。(Statement或Preparestatement)。
可以减少网络交互次次数,通过源码可以发现批处理中最佳时间就是同样的sql要一起执行,不要存在不同sql间隔这样的场景出现