首页 > 其他分享 >Statement 和 PreparedStatement总结

Statement 和 PreparedStatement总结

时间:2023-01-03 10:31:40浏览次数:43  
标签:总结 语句 PreparedStatement 编译 参数 Statement SQL


一、Statement


Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。


用于执行静态 SQL 语句并返回它所生成结果的对象。
在默认情况下,同一时间每个 Statement 对象在只能打开一个 ResultSet 对象。因此,如果读取一个 ResultSet 对象与读取另一个交叉,则这两个对象必须是由不同的 Statement 对象生成的。如果存在某个语句的打开的当前 ResultSet 对象,则 Statement 接口中的所有执行方法都会隐式关闭它。
Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL 语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和 CallableStatement(它从 PreparedStatement 继承而来)。它们都专用于发送特定类型的 SQL 语句: Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存在的存储过程的调用。
Statement 接口提供了执行语句和获取结果的基本方法。PreparedStatement 接口添加了处理 IN 参数的方法;而 CallableStatement 添加了处理 OUT 参数的方法。
使用案例:




Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table");


Statement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。



二、PreparedStatement


该 PreparedStatement接口继承Statement,并与之在两方面有所不同:
PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。
由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。


作为 Statement 的子类,PreparedStatement 继承了 Statement 的所有功能。另外它还添加了一整套方法,用于设置发送给数据库以取代 IN 参数占位符的值。同时,三种方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数。这些方法的 Statement 形式(接受 SQL 语句参数的形式)不应该用于 PreparedStatement 对象。


使用案例:


PreparedStatement pstmt = con.prepareStatement("UPDATE table SET name = ? WHERE age= ?");


在执行 PreparedStatement 对象之前,必须设置每个 ? 参数的值。这可通过调用 setXXX 方法来完成,其中 XXX 是与该参数相应的类型。例如,如果参数具有Java 类型 String,则使用的方法就是 setString。setXXX 方法的第一个参数是要设置的参数的序数位置,第二个参数是设置给该参数的值。例如,以下代码将第一个参数设为 tom,第二个参数设为 10:


pstmt.setLong(1, tom);


pstmt.setLong(2, 10);



一旦设置了给定语句的参数值,就可用它多次执行该语句,直到调用clearParameters 方法清除它为止。在连接的缺省模式下(启用自动提交),当语句完成时将自动提交或还原该语句。


三、比较


开发中应该始终以PreparedStatement代替Statement,原因如下:


1.代码的可读性和可维护性.
  虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次:
  stmt.executeUpdate("insertintotb_name(col1,col2,col2,col4)values('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
  perstmt=con.prepareStatement("insertintotb_name(col1,col2,col2,col4)values(?,?,?,?)");
  perstmt.setString(1,var1);
  perstmt.setString(2,var2);
  perstmt.setString(3,var3);
  perstmt.setString(4,var4);
  perstmt.executeUpdate();
  不用我多说,对于第一种方法.别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心.
2.PreparedStatement尽最大可能提高性能.
每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句有可能被重复调用.所以语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行.而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如:
  insertintotb_name(col1,col2)values('11','22');
  insertintotb_name(col1,col2)values('11','23');
  即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.
  当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.
  三.最重要的一点是极大地提高了安全性.
  即使到目前为止,仍有一些人连基本的恶义SQL语法都不知道.
  Stringsql="select*fromtb_namewherename='"+varname+"'andpasswd='"+varpasswd+"'";
  如果我们把['or'1'='1]作为varpasswd传入进来.用户名随意,看看会成为什么?
  select*fromtb_name='随意'andpasswd=''or'1'='1';
  因为'1'='1'肯定成立,所以可以任何通过验证.更有甚者:
  把[';droptabletb_name;]作为varpasswd传入进来,则:
  select*fromtb_name='随意'andpasswd='';droptabletb_name;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行.
  而如果你使用预编译语句.你传入的任何内容就不会和原来的语句发生任何匹配的关系.只要全使用预编译语句,你就用不着对传入的数据做任何过虑.而如果使用普通的statement,有可能要对drop,;等做费尽心机的判断和过虑.











标签:总结,语句,PreparedStatement,编译,参数,Statement,SQL
From: https://blog.51cto.com/u_15928064/5984731

相关文章

  • vue组件通信6种方式总结(常问知识点)
    前言在Vue组件库开发过程中,Vue组件之间的通信一直是一个重要的话题,虽然官方推出的Vuex状态管理方案可以很好的解决组件之间的通信问题,但是在组件库内部使用Vuex往往会......
  • 阿里前端二面必会react面试题总结
    非嵌套关系组件的通信方式?即没有任何包含关系的组件,包括兄弟组件以及不在同一个父级中的非兄弟组件。可以使用自定义事件通信(发布订阅模式)可以通过redux等进行全局状态......
  • 我的2022年终总结:再次抉择,以终为始
    2022年即将结束,又到了做年终总结的时候,它是我每年的一个习惯,意味着又要开始新的征途,在开始新的征途之前回顾一下很有必要。1也谈2022艰难抉择:从互联网到制造业今年最大......
  • 数据结构基础笔记、基础知识总结、周周练汇总,通过代码,更快速掌握数据结构和算法知识!
    目录​​快报快报!​​​​1.为什么要开通这个QQ群?​​​​2.里面都有啥?​​​​1、数据结构基础笔记​​​​2、数据结构必备基本知识​​​​3、数据结构周周练​​​​说......
  • 2022年总结-惊喜,尝试,忙碌,规划
    2022年已经结束,2023年悄然开始;一年的时间已经结束,回望2022年总结出四个词,惊喜,尝试,忙碌,规划。惊喜在于2022年5月的时候突然要转变身份了,要承担更多的责任,学会一个新的角......
  • C# winform 开发总结 -- 【持续更新】
    此文章将记录我在C#Winform开发过程中遇到的问题及相关知识技术点,方便自己以后查阅..... ​​C#在多线程中如何调用Winform​​问题的产生:我的WinForm程序中有一......
  • C/C++ 开发总结 -- 【持续更新】
    此文章将记录我在C/C++开发过程中遇到的问题及相关知识技术点,方便自己以后查阅.....博客列表​​C++中vector结合迭代器实现增删操作!​​删除vector里面多个符合条件的......
  • 调试Python程序的几种方法总结
    程序能一次写完并正常运行的概率很小,基本不超过1%。总会有各种各样的bug需要修正。有的bug很简单,看看错误信息就知道,有的bug很复杂,我们需要知道出错时,哪些变量的值是正确的,......
  • 客户端与服务器之间双向通讯的5种方式总结(完整代码演示)
    客户端与服务器之间双向通讯的5种方式总结(完整代码演示)  目录1.polling轮循2.long-polling长轮循3.iframe流4.EventSource流5.websocket 首......
  • 鸿蒙卡片开发-总结篇
    1.鸿蒙卡片概念官方描述:服务卡片(以下简称“卡片”)是​​FA​​的一种界面展示形式,将FA的重要信息或操作前置到卡片,以达到服务直达,减少体验层级的目的。开发文档:​​harmonyo......