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函数的差别

具体代码实现:

@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更改成下面的形式:这里使用了可变参数,而不是使用数组

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来连接的三个字段,只要有一个为真就可以将查询工作完成.

下面我们看下具体的代码实现:

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

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

使用PreparedStatement有几个好处 :

1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
       2. 安全性好,有效防止Sql注入等问题。 
       3.对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch; 
       4.代码的可读性和可维护性。

JDBC学习笔记——PreparedStatement的使用的更多相关文章

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

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

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

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

  3. JDBC学习笔记二

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

  4. JDBC学习笔记一

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

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

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

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

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

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

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

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

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

  9. 【转】JDBC学习笔记(1)——JDBC概述

    转自:http://www.cnblogs.com/ysw-go/ JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据 ...

随机推荐

  1. swift的关联类型

    一.术语:指定类型 typealias:用于给关联类型指定类型: 通过类型推断给关联类型指定类型太过烧脑: 二.类型指定 1.具体类型实现协议后,直接指定:作为普通的泛型类型使用,指定类型即可: 2. ...

  2. 《深入理解JVM》读书笔记

    目前只是整理了书的前几章,把jvm的内存划分简要说明.垃圾回收算法.垃圾回收器.常用的命令和工具进行说明.命令和工具的使用找个时间需要详细按步骤截图说明. 还有一部分内容是举例说明了一下字节码指令的样 ...

  3. tarjan【模板】缩点

    传送门:https://www.luogu.org/problemnew/show/P3387 首先呢,tarjan找一个图的强连通分量是基于对图的dfs的.这中间开了一个dfn[]代表dfs序,还有 ...

  4. 包、继承、Super、方法重写

    1 包_继承 1.1 包 包(package) 用于管理程序中的类,主要用于解决类的同名问题.包可以看出目录. 包的作用 [1] 防止命名冲突. [2] 允许类组成一个单元(模块),便于管理和维护 [ ...

  5. MetaMask/provider-engine-3-test

    通过看其test的代码去好好看看它是怎么使用的 1. provider-engine/test/basic.js const test = require('tape') const Provider ...

  6. HackerRake平台说明和介绍

    这是之前调研的时候稍微做了一个大致的总结,现在将其分享出去,感觉放在自己的文档管理库中,用处有限.分享出去,说不定能给一些朋友带来有益的启发. 另外我们团队最近也在考虑开发OJ平台.HackerRak ...

  7. dubbo接口访问控制

    微服务背景下,一个web应用都可能不再service依赖,而是通过RPC调用远端服务器上的服务.这些服务里,就包括了一些不能轻易暴露的后台功能接口.暴露出去的dubbo接口注册到某一个zk上后,该du ...

  8. JAVA框架:hibernate(二)

    一.事务操作. 代码: @Test public void tr_Up(){ Session session=hibernateUtils.getSession(); Transaction tran ...

  9. python+requests实现接口测试 - cookies的使用 (转载)

    出自:https://www.cnblogs.com/nizhihong/p/6699492.html 在很多时候,发送请求后,服务端会对发送请求方进行身份识别,如果请求中缺少识别信息或存在错误的识别 ...

  10. Android 写一个Activity之间来回跳转的全局工具类(主要是想实现代码的复用)

    废话不多说了,直接上代码,相信大家都能看得懂的. 一.主要工具类 package com.yw.chat.utils; import android.app.Activity; import andr ...