当前位置 博文首页 > GooReey的博客:【MyBatis 6】Statement、PreparedStatement,如
它们都是接口:
Statement:直接操作sql,不进行预编译,不带参数;
PreparedStatement:进行预编译,可带参数;
CallableStatement:执行存储过程;
SQL的执行需要编译和解析。
Statement每次的执行都需要编译SQL。
PreparedStatement会预编译,会被缓冲,在缓存区中可以发现预编译的命令,虽然会被再次解析,但不会被再次编译,能够有效提高系统性能。
用于产生单个结果集的语句,用于执行 SELECT 语句(SELECT无疑是是使用最多的 SQL 语句) ,返回值为ResultSet。
用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。
executeUpdate 的返回值是一个整数,指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。
用于执行返回多个结果集、多个更新计数或二者组合的语句。execute对与结果的处理比较麻烦
execute方法应该仅在语句能返回多个ResultSet对象、多个更新计数或ResultSet对象与更新计数的组合时使用。
返回值指示类型情况:如果下一个结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在更多结果,则返回 false。
Statement stmt = conn.createStatement();
if(stmt.execute(sql)){
ResultSet rs = stmt.getResultSet();
}else{
log.info("受影响的行 {}", stmt.getUpdateCount());
}
(1)ResultSet getResultSet()
以 ResultSet 对象的形式获取当前结果
(2)int getUpdateCount()
以更新计数的形式获取当前结果;如果结果为 ResultSet 对象或没有更多结果,则返回 -1
(3)boolean getMoreResults()
移动到此 Statement 对象的下一个结果,如果其为 ResultSet 对象,则返回 true,并隐式关闭利用方法 getResultSet 获取的所有当前 ResultSet 对象
(4)boolean getMoreResults(int current)
将此 Statement 对象移动到下一个结果,根据给定标志指定的指令处理所有当前 ResultSet 对象;如果下一个结果为 ResultSet 对象,则返回 true
(5)default long getLargeUpdateCount()
(1)void addBatch(String sql)
将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中
(2)void clearBatch()
清空此 Statement 对象的当前 SQL 命令列表
(3)int[] executeBatch()
?将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组?????????????????
对于batch操作,简单说就是有一个列表,保存了执行命令。
add是添加方法,clear就是清空方法,execute就是执行列表内命令。
如下面示例,将1000个“张三”分十次插入数据库:
for(int i=0;i<1000;i++){
String sql = "insert into user(id,name,age) values (i,'张三"+i+"',18)";
stmt.addBatch(sql);
if(i%100 == 0){
stmt.executeBatch();
stmt.clearBatch();
}
}
在此 PreparedStatement 对象中执行 SQL 语句,该语句可以是任何种类的 SQL 语句。
ResultSet executeQuery()
在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。
在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。
将一组参数添加到此 PreparedStatement 对象的批处理命令中。
立即清除当前参数值。
获取包含有关 ResultSet 对象列信息的 ResultSetMetaData 对象,ResultSet 对象将在执行此 PreparedStatement 对象时返回
获取此 PreparedStatement 对象的参数的编号、类型和属性。
String sql = "insert into user(id,name,age) values (?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
ps.setInt(1,1);
ps.setString(2,"哪吒");
ps.setInt(3,18);
ps.executeUpdate();
假如登录SQL为select * from user where name='zs' and password='123' ,如果在登录框密码处输入 “123 or 1=1”,那么SQL就成为了
select * from user where name='zs and password='123' or 1=1? ,这就是SQL注入。
所谓SQL注入就是将SQL语句片段插入到被执行的语句中,把SQL命令插入到Web表单提交或者输入域名或者页面请求的查询字符串,最终达到欺骗服务器,达到执行恶意SQL命令的目的。
PreparedStatement通过预编译,原有的SQL语句中的参数转换为占位符?的形式,相当于变成了填空题,不管你输入的内容是什么,都是作为参数,而不可能作为SQL的一部分
(要注意 #与$的区别)
你把密码输入为'123 or 1=1'然后提交,他会转换为? select * from user where name='zs and password='123?or 1=1',输入内容都转换为纯粹参数。
CallableStatement继承自prepareStatement,实现了存储过程函数调用的方法以及对于输出的处理。
CallableStatement调用存储过程和函数,一个很重要的部分就是输出的处理。
在JDBC中需要使用registerOutParameter将参数注册为输出,registerOutParameter的责任就是申明XXX参数是一个输出。
对于这个参数可以使用int? parameterIndex 下标索引(1开始)也可以使用String parameterName来指明,对于参数对应的类型也需要指明。
在mapper文件中可以使用statementType标记使用什么的对象操作SQL语句。
xml文件中通过statementType参数,选择适合的对象。
statementType取值说明:
注意:如果只为STATEMENT,那么sql就是直接进行的字符串拼接,这样为字符串需要加上引号,如果为PREPARED,是使用的参数替换,也就是索引占位符,我们的#会转换为?再设置对应的参数的值。
往期精彩内容:
Java知识体系总结
Spring框架总结
超详细的springBoot学习笔记
常见数据结构与算法整理总结
Java设计模式:23种设计模式全面解析
Java面试题总结(附答案)
Linux知识体系总结
Redis知识体系总结
cs