转自: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. 使用Compute Shader加速Irradiance Environment Map的计算

    Irradiance Environment Map基本原理 Irradiance Environment Map(也叫Irradiance Map或Diffuse Environment Map), ...

  2. 浅谈Java的集合体系

    集合体系框架图 集合接口 Java集合类库将接口(interface)与实现(implementation)分离,如上图,Set是一个集合接口,而HashSet与TreeSet都是实现了Set接口的子 ...

  3. BOM基础(一)

    学完了js的基础语法和DOM之后,就要要看看javascript中最后一项BOM了.BOM,全称brower document model,翻译过来就是浏览器对象模型.DOM是文档对象模型,属于BOM ...

  4. 雪花降落CADisplayLink

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC"; color: #1d9421 } p.p2 ...

  5. iOS 获取手机型号,系统版本

    新添加判断iPhone 7.iPhone 7 Plus ,我手里没有7,判断不对表打我~ FQ找的资料:http://www.iphonehacks.com/download-iphone-ios-f ...

  6. Struts 基本概念,优点及不同版本之间的关系

    strutx 1.x struts 是 apache 基金会的一个开源项目. struts 是一套实现 MVC的框架. MVC = 程序分层设计的思想 = Model(数据访问层1) / View(视 ...

  7. intellij idea打jar包时的注意事项

    intellij idea项目在打包maven项目时,数据路径很容易出现问题.在IDE内直接运行不会报错,但打成jar包运行就会报错. intellij打包的几种方式:http://www.cnblo ...

  8. 一个蛋疼的CTF图片隐写

    话不多说,直接上原题 TIPS:心中无码 打开解题链接,是一张png图片,直接用16进制编辑器打开,没有附加其它文件.看下文件区段信息也很正常. 又拖进stegsolve,Blue的0位很不正常 多次 ...

  9. (17)IO中的异常处理

    public static void copyImage() throws IOException { //找到目标文件 File inFile = new File("D:\\1.jpg& ...

  10. windows phone 8.1开发:文件选择器FileSavePicker

    上一篇文章小梦分享了文件选择器FileOpenPicker的用法,这篇文章我们继续分享FileSavePicker的用法,FileSavePicker的用法几乎和FileOpenPicker用法一模一 ...