转自:http://www.cnblogs.com/ysw-go/

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注入的问题。

【转】JDBC学习笔记(4)——PreparedStatement的使用的更多相关文章

  1. JDBC学习笔记(4)——PreparedStatement的使用

    PreparedStatement public interface PreparedStatement extends Statement;可以看到PreparedStatement是Stateme ...

  2. JDBC 学习笔记(六)—— PreparedStatement

    1. 引入 PreparedStatement PreparedStatement 通过 Connection.createPreparedStatement(String sql) 方法创建,主要用 ...

  3. JDBC 学习笔记(十)—— 使用 JDBC 搭建一个简易的 ORM 框架

    1. 数据映射 当我们获取到 ResultSet 之后,显然这个不是我们想要的数据结构. 数据库中的每一个表,在 Java 代码中,一定会有一个类与之对应,例如: package com.gerrar ...

  4. JDBC学习笔记二

    JDBC学习笔记二 4.execute()方法执行SQL语句 execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象 ...

  5. JDBC学习笔记一

    JDBC学习笔记一 JDBC全称 Java Database Connectivity,即数据库连接,它是一种可以执行SQL语句的Java API. ODBC全称 Open Database Conn ...

  6. JDBC 学习笔记(十一)—— JDBC 的事务支持

    1. 事务 在关系型数据库中,有一个很重要的概念,叫做事务(Transaction).它具有 ACID 四个特性: A(Atomicity):原子性,一个事务是一个不可分割的工作单位,事务中包括的诸操 ...

  7. JDBC学习笔记(2)——Statement和ResultSet

    Statement执行更新操作 Statement:Statement 是 Java 执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句.Statement ...

  8. JDBC学习笔记(1)——JDBC概述

    JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据库连接. JDBC库中所包含的API任务通常与数据库使用: 连接到数 ...

  9. 【转】JDBC学习笔记(2)——Statement和ResultSet

    转自:http://www.cnblogs.com/ysw-go/ Statement执行更新操作 Statement:Statement 是 Java 执行数据库操作的一个重要方法,用于在已经建立数 ...

随机推荐

  1. 安全体系(二)——RSA算法详解

    本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...

  2. Java调度框架Quartz简单示例

    Quartz的大名如雷贯耳,这里就不赘述,而且本文也不作为深入探讨,只是看完Quartz的官方文档后,下个简单示例,至少证明曾经花了点时间学习过,以备不时之需. Quartz使用了SLF4J,所以至少 ...

  3. React组件开发经典案例--todolist

    点开查看代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <me ...

  4. java基础:模拟ATM取款机

    package com.atm; import java.util.Scanner; /** * ATM类实现 * * @author 向往的生活 */ public class ATM { publ ...

  5. ajax 实现加载页面、删除、查看详细信息,以及bootstrap网页的美化

      由于有些的程序员可能不是很会Photoshop,所以为了美化页面,我们可以借助工具bootstrap,实现起来相对就要比之前做的美观一些, 今天我用bootstrap把之前做的显示表格进行了一下美 ...

  6. 网络安全实验室 脚本关通关writeup

    [1]key又又找不到了查看源代码.发现key的路径,点击进行了302跳转,抓包,得到key [2]快速口算要2秒内提交答案,果断上python import requests,re s = requ ...

  7. JAVA面试题和答案

    本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的章节分为上下两篇,第一篇将要讨论面向对象编程和它的特点,关于Java和它的功能 ...

  8. Octave Tutorial(《Machine Learning》)之第一课《数据表示和存储》

    Octave Tutorial 第一课 Computation&Operation 数据表示和存储 1.简单的四则运算,布尔运算,赋值运算(a && b,a || b,xor( ...

  9. 深度学习实践系列(1)- 从零搭建notMNIST逻辑回归模型

    MNIST 被喻为深度学习中的Hello World示例,由Yann LeCun等大神组织收集的一个手写数字的数据集,有60000个训练集和10000个验证集,是个非常适合初学者入门的训练集.这个网站 ...

  10. linux下mysql的大小写是否区分设置

    转:http://blog.csdn.net/qq_29246225/article/details/52293549 一.Linux中MySQL大小写详情:1.数据库名严格区分大小写2.表名严格区分 ...