执行sql语句为什么?用PreparedStatement要比Statement好用
PreparedStatement
public interface PreparedStatement extends Statement;可以看到PreparedStatement是Statement的子接口,我们在执行查询或者更新数据表数据的时候,拼写SQL语句是一个很费力并且容易出错的事情,PreparedStatement可以简化这样的一个过程.
PreParedStatement
1).why?我们为什么要使用它
使用Statement需要进行拼写SQl语句,辛苦并且容易出错,之前使用Statement的SQL语句的形式是这样的
String sql = "insert into examstudent" + " values("
+ student.getFlowId() + "," + student.getType() + ",'"
+ student.getIdCard() + "','" + student.getExamCard() + "','"
+ student.getStudentName() + "','" + student.getLocation()
+ "'," + student.getGrade() + ")";
使用PreparedStatement:是Statement的子接口,可以传入带占位符的SQL语句,提供了补充占位符变量的方法
PreparedStatement ps=conn.preparedStatement(sql);
可以看到将sql作为参数传入了,就不需要我们在费力拼写了。
2)变成了这样的形式
String sql="insert into examstudent values(?,?,?,?,?,?,?)";
可以调用PreparedStatement的setXxx(int index,Object val)设置占位符的值,其中index的值从1开始
执行SQl语句:excuteQuery()或者excuteUpdate()就可以完成查询或者数据的更新.【注意】:此时函数的参数位置不需要传入SQL语句,注意同使用Statement的update函数的差别
具体代码实现:

1 @Test
2 public void testPreparedStatement() {
3 Connection connection = null;
4 PreparedStatement preparedStatement = null;
5 try {
6 // 连接数据库
7 connection = JDBCTools.getConnection();
8 // 使用占位符的SQl语句
9 String sql = "insert into customers(name,email,birth)"
10 + "values(?,?,?)";
11 // 使用preparedStatement的setXxx方法设置每一个位置上的值
12 preparedStatement = connection.prepareStatement(sql);
13 // 设置name字段
14 preparedStatement.setString(1, "ATGUIGU");
15 // 设置email字段
16 preparedStatement.setString(2, "simale@163.com");
17 // 设置birth字段
18 preparedStatement.setDate(3,
19 new Date(new java.util.Date().getTime()));
20 // 执行更新操作
21 preparedStatement.executeUpdate();
22 } catch (Exception e) {
23 e.printStackTrace();
24 } finally {
25 // 释放资源
26 JDBCTools.release(null, preparedStatement, connection);
27 }
28 }

使用PreparedStatement执行SQl(更新操作:插入、删除、更新,但不包括select查询操作),JDBCTools中的通用函数update更改成下面的形式:这里使用了可变参数,而不是使用数组

1 public static void update(String sql,Object ...args){
2 /**
3 * 执行SQL语句,使用PreparedStatement
4 */
5 Connection connection=null;
6 PreparedStatement preparedStatement=null;
7 try {
8 connection=JDBCTools.getConnection();
9 preparedStatement=connection.prepareStatement(sql);
10 for(int i=0;i<args.length;i++){
11 preparedStatement.setObject(i+1, args[i]);
12 }
13 preparedStatement.executeUpdate();
14 } catch (Exception e) {
15 e.printStackTrace();
16 }finally{
17 JDBCTools.release(null, preparedStatement, connection);
18 }
19 }

使用PreparedStatement的好处:
1).提高代码的可读性和可维护性;
2).最大程度的提高性能:JDBC驱动的最佳化是基于使用的是什么功能. 选择PreparedStatement还是Statement取决于你要怎么使用它们. 对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的.PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行(缓存的作用). 例如, 假设我使用Employee ID, 使用prepared的方式来执行一个针对Employee表的查询. JDBC驱动会发送一个网络请求到数据解析和优化这个查询. 而执行时会产生另一个网络请求. 在JDBC驱动中,减少网络通讯是最终的目的. 如果我的程序在运行期间只需要一次请求, 那么就使用Statement. 对于Statement, 同一个查询只会产生一次网络到数据库的通讯.当使用PreparedStatement池时, 如果一个查询很特殊, 并且不太会再次执行到, 那么可以使用Statement. 如果一个查询很少会被执行,但连接池中的Statement池可能被再次执行, 那么请使用PreparedStatement. 在不是Statement池的同样情况下, 请使用Statement.
3).可以防止SQL注入
SQL注入指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
比如我们新建一个数据表users,表中有两个字段username和password;

我们在图形化界面SQLyog的sql语句的查询界面输入这样的查询语句:select * from users where username='a' or password='and password=' or '1'='1';
执行该语句,会得到我们表中的数据:

我们可以分析一下这条语句:where的后面,通过多个字段的组合作为查询过滤的条件。
字段一:username='a'
字段二:password='and password='
字段三:'1'='1'
因为用逻辑连接符OR来连接的三个字段,只要有一个为真就可以将查询工作完成.
下面我们看下具体的代码实现:

1 @Test
2 public void testSQLinjection() {
3 String username = "a' or password =";
4 String password = " or '1'='1";
5 String sql = "select * from users where username='" + username
6 + "' AND " + "password='" + password + "'";
7 System.out.println(sql);
8 Connection connection = null;
9 Statement statement = null;
10 ResultSet resultSet = null;
11 try {
12 connection = getConnection();
13 statement = connection.createStatement();
14 resultSet = statement.executeQuery(sql);
15 if (resultSet.next()) {
16 System.out.println("登陆成功");
17 } else {
18 System.out.println("不匹配");
19 }
20 } catch (Exception e) {
21 e.printStackTrace();
22 } finally {
23 JDBCTools.release(resultSet, statement, connection);
24 }
25 }

运行结果:
select * from users where username='a' or password =' AND password=' or '1'='1'
登陆成功
可以看到我们的SQl语句中都没有明确我们要查的字段的名,但是还是获取了查询的结果(SQL语句太能混了)
于是,我们用了PreparedStatement就可以解决SQL注入的问题。

1 @Test
2 public void testSQLinjection2() {
3 String username = "a' or password =";
4 String password = " or '1'='1";
5 String sql = "select * from users where username=?" + " and password=?";
6 System.out.println(sql);
7 Connection connection = null;
8 PreparedStatement preparedStatement = null;
9 ResultSet resultSet = null;
10 try {
11 connection = getConnection();
12 preparedStatement = connection.prepareStatement(sql);
13 preparedStatement.setString(1, username);
14 preparedStatement.setString(2, password);
15 resultSet = preparedStatement.executeQuery();
16 if (resultSet.next()) {
17 System.out.println("登陆成功");
18 } else {
19 System.out.println("不匹配");
20 }
21 } catch (Exception e) {
22 e.printStackTrace();
23 } finally {
24 JDBCTools.release(resultSet, preparedStatement, connection);
25 }
26 }

执行结果:
select * from users where username=? and password=?
不匹配
可以看到:再次使用伪装后的SQL语句已经不能获取我们数据表中的信息,我们这里在sql语句中使用了占位符。因此使用PreparedStatement可以结解决这里的SQL注入的问题。
<%@ page language="java" import="java.sql.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>插入界面</title>
</head> <body>
<%
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
//加载JDBC驱动
String dbURL = "jdbc:sqlserver://localhost:1433; DatabaseName=JSPTest";
//连接服务器和数据库
String userName = "sa"; //默认用户名
String userPwd = "123456"; //密码
Class.forName(driverName);
Connection Conn = DriverManager.getConnection(dbURL, userName, userPwd);
System.out.println("Connection Successful!");
String sql="Insert into regist(ID,password) values(?,?)";
PreparedStatement pstmt=Conn.prepareStatement(sql);
pstmt.setString(1, "201504");
pstmt.setInt(2, 111);
int n=pstmt.executeUpdate();
if(n==1){%>数据插入成功!<br><%}
else{%>数据插入失败!<br><%}
%>
</body>
</html>
执行sql语句为什么?用PreparedStatement要比Statement好用的更多相关文章
- 使用预处理PreparedStatement执行Sql语句
/** * 使用预处理的方式执行Sql * @param sql Sql语句 * @param obj 变量值数组 * @return 查询结果 * @throws SQLException */ p ...
- [疯狂Java]JDBC:PreparedStatement预编译执行SQL语句
1. SQL语句的执行过程——Statement直接执行的弊病: 1) SQL语句和编程语言一样,仅仅就会普通的文本字符串,首先数据库引擎无法识别这种文本字符串,而底层的CPU更不理解这些文本字符串( ...
- JDBC进阶之PreparedStatement执行SQL语句(MySQL)
一.什么是PreparedStatement 参阅Java API文档,我们可以知道,PreparedStatement是Statement的子接口(如图所示),表示预编译的 SQ ...
- Statement和PreparedStatement都是用来发送和执行SQL语句的
Statement和PreparedStatement都是用来发送和执行SQL语句的 DriverManager管理一组驱动程序
- 三种执行SQL语句的的JAVA代码
问题描述: 连接数据库,执行SQL语句是必不可少的,下面给出了三种执行不通SQL语句的方法. 1.简单的Statement执行SQL语句.有SQL注入,一般不使用. public static voi ...
- 在mybatis执行SQL语句之前进行拦击处理
转载自:http://blog.csdn.net/hfmbook/article/details/41985853 比较适用于在分页时候进行拦截.对分页的SQL语句通过封装处理,处理成不同的分页sql ...
- JDBC详解系列(四)之建立Stament和执行SQL语句
建立Stament 在获得连接之后,我们就可以跟数据库进行交互了. 在JDBC中,我们发送SQL语句到数据库这些操作时通过Stament,Preparement,CallableStateme ...
- JDBC中执行SQL语句的方式
一.执行DDL.DML语句 DDL.DML分别表示数据库定义语言.数据库操纵语言,操控这两种语言应该使用Statement对象的executeUpdate方法. 代码如下: public static ...
- executeBatch()批量执行Sql语句
executeBatch()方法:用于成批地执行SQL语句,但不能执行返回值是ResultSet结果集的SQL语句,而是直接执行stmt.executeBatch(); addBatch():向批处理 ...
随机推荐
- 『Argparse』命令行解析
一.基本用法 Python标准库推荐使用的命令行解析模块argparse 还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的optparse.因为argparse是 ...
- git提交代码到码云详解
一.为什么不用github而使用码云? 私有——免费,速度快 二.怎么用? 1.下载安装好git. 2.去码云官网注册个账号.官网:https://git.oschina.net/ 3.创建项目.项目 ...
- ndarray对象的使用方法
ndarray的基本操作 1.索引 基本索引:一维与list完全一致 多维同理 例如: import numpy ndarr1 = numpy.random.randint(0,10.size=5) ...
- MySQL字符串列与整数比较
一.问题说明 为了简便在存储时我们经常将整型字段也以字符串形式存储(如id值),但在筛选比较时就需要将该字段转为数值类型. 二.处理办法 2.1 使用cast函数进行类型转换 cast函数格式---- ...
- day20_python_1124
01 昨日内容回顾 类的名称空间 对象的空间 class A: def __init__(): pass obj = A() 对象查询属性:对象本身 ----> 类 -----> 父类 类 ...
- scrapy的Middleware
对于下载中间件 settings里的数字大小: process_request的顺序 数字越小,越先调用 process_response 的顺序, 数字越大,越先调用 返回值: process_re ...
- C#获取程序运行时间
需要用到System.Diagnostics名称空间中的Stopwatch类! Stopwatch类其中有一个属性ElapsedMilliseconds.该属性是获取当前运行时间,以毫秒为单位! 其中 ...
- Unity用GUI绘制Debug/print窗口/控制台-打包后测试
Unity游戏视窗控制台输出 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...
- # 20175120 2018.3.3 《Java程序设计》第1周学习总结
## 教材学习内容总结 1.安装ubuntu,在实验楼学习liunx系统各种功能的实现.2.在ubuntu平台上进行java程序的编写3.学会使用JDB调试java程序,并将代码上传到码云上4.学习j ...
- Linux下查看CPU型号,内存大小,硬盘空间的命令(详解)
1 查看CPU 1.1 查看CPU个数 # cat /proc/cpuinfo | grep "physical id" | uniq | wc -l 2 **uniq命令:删除重 ...