【Java】PreparedStatement VS Statement
创建时:
Statement statement = conn.createStatement();
PreparedStatement preStatement = conn.prepareStatement(sql);
执行时:
ResultSet rSet = statement.executeQuery(sql);
ResultSet pSet = preStatement.executeQuery();
由上可以看出,PreparedStatement有预编译的过程,已经绑定sql,之后无论执行多少遍,都不会再去进行编译,
而 statement 不同,如果执行多变,则相应的就要编译多少遍sql,所以从这点看,preStatement 的效率会比 Statement要高一些。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement; public class JDBCTest {
public static void main(String[] args) throws Exception {
//1 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取数据库连接
String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, user, password);
//3 创建一个Statement
String sql = "select id,loginName,email from user where id=";
String tempSql;
int count = 1000;
long time = System.currentTimeMillis();
for(int i=0 ;i<count ;i++){
Statement statement = conn.createStatement();
tempSql=sql+(int) (Math.random() * 100);
ResultSet rSet = statement.executeQuery(tempSql);
statement.close();
}
System.out.println("statement cost:" + (System.currentTimeMillis() - time));
String psql = "select id,loginName,email from user where id=?";
time = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
int id=(int) (Math.random() * 100);
PreparedStatement preStatement = conn.prepareStatement(psql);
preStatement.setLong(1, new Long(id));
ResultSet pSet = preStatement.executeQuery();
preStatement.close();
}
System.out.println("preStatement cost:" + (System.currentTimeMillis() - time));
conn.close();
}
}
上述代码反复执行,
statement cost:95 preStatement cost:90
statement cost:100 preStatement cost:89
statement cost:92 preStatement cost:86
当然,这个也会跟数据库的支持有关系,http://lucaslee.iteye.com/blog/49292 这篇帖子有说明
虽然没有更详细的测试 各种数据库, 但是就数据库发展 版本越高,数据库对 preStatement的支持会越来越好,
所以总体而言, 验证 preStatement 的效率 比 Statement 的效率高
2>安全性问题
这个就不多说了,preStatement是预编译的,所以可以有效的防止 SQL注入等问题
所以 preStatement 的安全性 比 Statement 高
3>代码的可读性 和 可维护性
这点也不用多说了,你看老代码的时候 会深有体会
preStatement更胜一筹
1 、PreparedStatement 接口继承 Statement , PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement对象。
2 、作为 Statement 的子类, PreparedStatement 继承了 Statement 的所有功能。三种方法
execute 、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数
3 、在 JDBC 应用中 , 如果你已经是稍有水平开发者 , 你就应该始终以 PreparedStatement 代替
Statement. 也就是说 , 在任何时候都不要使用 Statement.
基于以下的原因 :
一 . 代码的可读性和可维护性 .
虽然用 PreparedStatement 来代替 Statement 会使代码多出几行 , 但这样的代码无论从可读性还是可维护性上来说 . 都比直接用Statement 的代码高很多档次 :
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");//stmt 是 Statement 对象实例
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate(); //prestmt 是 PreparedStatement 对象实例
不用我多说 , 对于第一种方法 . 别说其他人去读你的代码 , 就是你自己过一段时间再去读 , 都会觉得伤心 。
PreparedStatement 尽最大可能提高性能 .
语句在被 DB 的编译器编译后的执行代码被缓存下来 , 那么下次调用时只要是相同的预编译语句就不需要编译 , 只要将参数直接传入编译过的语句执行代码中 ( 相当于一个涵数 ) 就会得到执行 . 这并不是说只有一个 Connection 中多次执行的预编译语句被缓存 , 而是对于整个 DB 中 , 只要预编译的语句语法和缓存中匹配 . 那么在任何时候就可以不需要再次编译而可以直接执行 . 而 statement 的语句中 , 即使是相同一操作 , 而由于每次操作的数据不同所以使整个语句相匹配的机会极小 , 几乎不太可能匹配 . 比如 :
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因为数据内容不一样 , 所以整个个语句本身不能匹配 , 没有缓存语句的意义 . 事实是没有数据库会对普通语句编译后的执行代码缓存 。
当然并不是所以预编译语句都一定会被缓存 , 数据库本身会用一种策略 , 比如使用频度等因素来决定什么时候不再缓存已有的预编译结果. 以保存有更多的空间存储新的预编译语句 .
三 . 最重要的一点是极大地提高了安全性 。
即使到目前为止 , 仍有一些人连基本的恶义 SQL 语法都不知道 .
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我们把 [' or '1' = '1] 作为 varpasswd 传入进来 . 用户名随意 , 看看会成为什么 ?
select * from tb_name = ' 随意 ' and passwd = '' or '1' = '1';
因为 '1'='1' 肯定成立 , 所以可以任何通过验证 . 更有甚者 :
把 [';drop table tb_name;] 作为 varpasswd 传入进来 , 则 :
select * from tb_name = ' 随意 ' and passwd = '';drop table tb_name; 有些数据库是不会让你成功的 , 但也有很多数据库就可以使这些语句得到执行 .
而如果你使用预编译语句 . 你传入的任何内容就不会和原来的语句发生任何匹配的关系 。
只要全使用预编译语句 , 你就用不着对传入的数据做任何过虑 。
而如果使用普通的 statement, 有可能要对 drop,; 等做费尽心机的判断和过虑 。
【Java】PreparedStatement VS Statement的更多相关文章
- 【Java】-NO.16.EBook.4.Java.1.012-【疯狂Java讲义第3版 李刚】- JDBC
1.0.0 Summary Tittle:[Java]-NO.16.EBook.4.Java.1.012-[疯狂Java讲义第3版 李刚]- JDBC Style:EBook Series:Java ...
- 【Java】-NO.20.Exam.1.Java.1.001- 【1z0-807】- OCEA
1.0.0 Summary Tittle:[Java]-NO.20.Exam.1.Java.1.001-[1z0-807] Style:EBook Series:Java Since:2017-10- ...
- 【Java】-NO.12.Java.2.OCJP.1.001-【Java OCJP】-
1.0.0 Summary Tittle:[Java]-NO.12.Java.2.OCJP.1.001-[Java OCJP]- Style:Java Series:OCJP Since:2017-0 ...
- 【Java】代处理?代理模式 - 静态代理,动态代理
>不用代理 有时候,我希望在一些方法前后都打印一些日志,于是有了如下代码. 这是一个处理float类型加法的方法,我想在调用它前打印一下参数,调用后打印下计算结果.(至于为什么不直接用+号运算, ...
- 【Java】推断文件的后缀名
这本来不是一个问题,利用框架本来有的方法.或者File类的getPath()方法,取出要推断文件路径.或者getName()方法取出文件路径,成为一个String字符串如果为fileName之后,再对 ...
- 【JAVA】【NIO】3、Java NIO Channel
Java NIO和流量相似,但有些差异: ·通道可读写,流仅支持单向.读或写 ·异步通道读取 ·通道读写器,他们是和Buffer交替 道的实现 下面是Java NIO中最重要的通道的实现: ·File ...
- 【JAVA】【NIO】5、Java NIO Scatter / Gather
标题手段Java NIO该分散体浓缩 Java NIO内置支持分散与收集.的概念主要用于信道分散聚集的读写. 读出的分散体的一个通道被读多个数据buffer在.因此.数据分散到多个buffer中. 对 ...
- 【Java】0X001.配置开发环境,JDK、classpath等
[Java]0x01 配置开发环境,JDK.CLASSPATH等 一. 下载JDK安装文件 首先,进入Oracle官网Java页面. 注意,要下载的是JDK而不是JRE,这点很重要,因为JRE并不包含 ...
- for循环输出空心菱形的形状【java】
使用for循环语句输出以下“空心菱形”效果: * * * * * * * * * * * * * * * * 建议优先参考笔者的另一篇文章:<for循环输出菱形的形状[java]> 代码: ...
随机推荐
- webpack window dev-server配置
1.安装webpack dev-server npm install --save-dev webpack webpack-dev-server 著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...
- 细说PHP中strlen和mb_strlen的区别(转)
在PHP中,strlen与mb_strlen是求字符串长度的函数,但是对于一些初学者来说,如果不看手册,也许不太清楚其中的区别.下面通过例子,讲解这两者之间的区别. 先看例子: <?php // ...
- sql中union 和 union all的区别
最近发现一个视图出奇的慢,在生产环境还好,由于服务器配置较高,没有察觉出来.但是做了一次修改后在开发版 和测试版就直接查询不出结果了.就连select count(1) from 都运行2个小时没有结 ...
- Linux C 编程一站式学习
个人认为这是一个挺不错的从C语言到Linux系统开发的教程,这本是两个网上的文档. 其中 一本是<How To Think Like A Computer Scientist: Learning ...
- 利用eclipse+jdk1.8搭建Java开发环境(超具体的)
利用eclipse+jdk1.8搭建Java开发环境 转载请声明出处:http://blog.csdn.net/u013067166/article/details/50267003 引言:eclip ...
- 使用Object#tap使代码更优雅
今天看spree源码的时候经常看到Object#tap方法.以前只知道有这个方法,而且感觉这个方法调试的作用大于实际,今日看来以前的理解应该不够准确. 先看下官方文档上tap的例子 Yields se ...
- Python 文件 readline() 方法
描述 Python 文件 readline() 方法用于从文件读取整行,包括 "\n" 字符.如果指定了一个非负数的参数,则返回指定大小的字符数,包括 "\n" ...
- 配置IISserver
我们自己开发站点的时候 要在自己的电脑上写网页 然后我们怎么能像我们浏览互联网上的网页一样.而不是直接双击打开网页呢 这时候就要配置IISserver 让自己能够 预览自己站点的效果 以下是 ...
- IAR for stm8 memory窗口的功能
进入debug模式后点击菜单view-Memory 可以在线查看,RAM,FLASH,OPTION等
- springboot 中使用Druid 数据源提供数据库监控
一.springboot 中注册 Servlet/Filter/Listener 的方式有两种,1 通过代码注册 ServletRegistrationBean. FilterRegistration ...