如何使用 PreparedStatement 来避免 SQL 注入,并提高性能?
前言
本篇文章主要如何使用 PreparedStatement 来避免 SQL 注入,并提高性能?
欢迎点赞 收藏 留言评论 私信必回哟
博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言
@
一,什么是 PreparedStatement ?
preparedStatement是一种预编译的SQL语句,它可以在执行时 动态地设置参数,从而提高SQL语句的执行效率和安全性。与普通的SQL语句不同,preparedStatement在执行前已经被编译成二进制代码,因此可以避免SQL注入攻击。
在Java中,使用preparedStatement可以通过以下步骤实现:
创建Connection对象,连接到数据库。
使用Connection对象创建preparedStatement对象,预编译SQL语句。
设置SQL语句中的参数。
执行SQL语句,获取结果集。
处理结果集,关闭连接。
例如:
以下代码演示关键部分代码如何使用 preparedStatement 查询 数据库中的用户信息:
//编写sql语句
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
//根据连接字符串连接数据库
Connection conn = DriverManager.getConnection(url, username, password);
//创建PreparedStatement 对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//传入参数
pstmt.setString(1, "john");
pstmt.setString(2, "password123");
//执行方式
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String username = rs.getString("username");
String password = rs.getString("password");
// 处理结果集 } rs.close(); pstmt.close(); conn.close();
}
//释放资源
rs.close();
pstmt.close();
conn.close();
二,为什么要使用PreparedStatement ?
使用 PreparedStatement 时,不需要拼接 SQL 语句,因此可以避免因字符串拼接而产生的 SQL 注入问题。Prepared Statement 可以对参数进行转义,从而避免输入的参数导致的 SQL 异常。Prepared Statement 可以预编译 SQL 语句,并将编译后的语句保存到数据库服务器的缓存中,因此在执行多次相同的 SQL 语句时,可以大幅提高性能。
1,通过PreparedStatement提升性能
Statement主要用于执行静态SQL语句,即内容固定不变的SQL语句。Statement每执行一次都要对传入的SQL语句编译一次,效率较差。
某些情况下,SQL语句只是其中的参数有所不同,其余子句完全相同,适用于PreparedStatement。PreparedStatement的另外一个好处就是预防sql注入攻击
PreparedStatement是接口,继承自Statement接口。
使用PreparedStatement时,SQL语句已提前编译,三种常用方法 execute、 executeQuery 和 executeUpdate 已被更改,以使之不再需要参数。
PreparedStatement 实例包含已事先编译的 SQL 语句,SQL 语句可有一个或多个 IN 参数,IN参数的值在 SQL 语句创建时未被指定。该语句为每个 IN 参数保留一个问号(“?”)作为占位符。
每个问号的值必须在该语句执行之前,通过适当的setInt或者setString 等方法提供。
由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。
通常批量处理时使用PreparedStatement。
做一个小实验:分别向数据库插入1000条记录。分别记录执行时间,然后进行比较。
使用Statement的执行效率 insert User_1表
/**
* // 使用Statement的 执行效率
* @throws Exception
*/
@Test
public void test1() throws Exception{
//c3p0 的数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
Connection conn = dataSource.getConnection();
Statement state = conn.createStatement();
long time1 = System.nanoTime();//获取纳秒级时间
for (int i = 0; i < 3000; i++) {
String sql = String.format("insert into user_1 values(%s,'%s',%s)",
i,"Test",20);
state.executeUpdate(sql);
}
System.out.println("插入完毕");
long time2 = System.nanoTime();//获取纳秒级时间
System.out.println("耗费时长:"+(time2-time1));
conn.close();
state.close();
}
测试数据
使用预编译PreparedStatement SQL提高执行效率 insert User_2表
/**
* 使用预编译PreparedStatement SQL提高执行效率
*/
@Test
public void test2() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
Connection conn = dataSource.getConnection();
String sql = "insert into user_2 values(?,?,?)";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
long time1 = System.nanoTime();//获取纳秒级时间
for (int i = 0; i < 3000; i++) {
preparedStatement.setInt(1,i);
preparedStatement.setString(2,"Test");
preparedStatement.setInt(3,20);
preparedStatement.execute();
}
System.out.println("插入完毕");
long time2 = System.nanoTime();//获取纳秒级时间
System.out.println("耗费时长:"+(time2-time1));
conn.close();
}
测试数据
2、通过PreparedStatement防止SQL Injection(注入)
对JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement无效,因为PreparedStatement不允许在插入参数时改变SQL语句的逻辑结构。
使用预编译的语句对象时,用户传入的任何数据不会和原SQL语句发生匹配关系,无需对输入的数据做过滤。如果用户将 ”or 1 = 1” 传入赋值给占位符,
下述SQL语句将无法执行:
select * from t where username = ? and password = ?;
PreparedStatement是Statement的子类,表示预编译的SQL语句的对象。在使用PreparedStatement对象执行SQL命令时,命令被数据库编译和解析,并放入命令 缓冲区。缓冲区中的预编译SQL命令可以重复使用。
三,Statement和PreparedStatement的区别
1、PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高
2、使用 Statement 对象。在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。
3、statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement预编译得, preparedstatement支持批处理 。
4、执行许多SQL语句的JDBC程序产生大量的Statement和PreparedStatement对象。通常认为PreparedStatement对象比Statement对象更有效,特别是如果带有不同参数的同一SQL语句被多次执行的时候。PreparedStatement对象允许数据库预编译SQL语句,这样在随后的运行中可以节省时间并增加代码的可读性。(使用PrepareStatement对象执行sql时,sql被数据库进行解析和编译,然后被放到命令缓冲区,每当执行同一个PrepareStatement对象时,它就会被解析一次,但不会被再次编译。在缓冲区可以发现预编译的命令,并且可以重用)
5、 PreparedStatement 可以规避 Statement弊端:①拼串 ②sql注入问题
6、PreparedStatement 可以实现操作Blob类型、Clob类型的数据
联系:
1、PreparedStatement继承自Statement
2、PrerapedStatement和Statement都是接口
3、PreParedStatement和Statement都可以实现对数据表的CRUD操作:增删改查
最后
总结不易,希望uu们不要吝啬你们的哟(^U^)ノ~YO!!
如有问题,欢迎评论区批评指正
如何使用 PreparedStatement 来避免 SQL 注入,并提高性能?的更多相关文章
- Statement和PreparedStatement的区别; 什么是SQL注入,怎么防止SQL注入?
问题一:Statement和PreparedStatement的区别 先来说说,什么是java中的Statement:Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接 ...
- PreparedStatement解决sql注入问题
总结 PreparedStatement解决sql注入问题 :sql中使用?做占位符 2.得到PreparedStatement对象 PreparedStatement pst=conn.prepar ...
- Statement和PreparedStatement的区别; 什么是SQL注入,怎么防止SQL注入? (转)
问题一:Statement和PreparedStatement的区别 先来说说,什么是java中的Statement:Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接 ...
- jdbc java数据库连接 8)防止sql注入
回顾下之前jdbc的开发步骤: 1:建项目,引入数据库驱动包 2:加载驱动 Class.forName(..); 3:获取连接对象 4:创建执行sql语句的stmt对象; 写sql 5:执行sql ...
- 预处理prepareStatement是怎么防止sql注入漏洞的?
序,目前在对数据库进行操作之前,使用prepareStatement预编译,然后再根据通配符进行数据填值,是比较常见的做法,好处是提高执行效率,而且保证排除SQL注入漏洞. 一.prepareStat ...
- JSP网页防止sql注入攻击
SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使 ...
- 使用jdbc拼接条件查询语句时如何防止sql注入
本人微信公众号,欢迎扫码关注! 使用jdbc拼接条件查询语句时如何防止sql注入 最近公司的项目在上线时需要进行安全扫描,但是有几个项目中含有部分老代码,操作数据库时使用的是jdbc,并且竟然好多都是 ...
- sql 注入 与解决
package cn.itcast.jdbc; import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLExce ...
- JDBC 及 sql注入问题
一.相关概念 1.什么是JDBC JDBC(Java Database Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由 ...
- 用java PreparedStatement就不用担心sql注入了吗?
先感慨下,好久没写博客了,一是工作太忙,二是身体不太给力,好在终于查清病因了,趁着今天闲下来,迫不及待与读者交流,最后忠告一句:身体是活着的本钱! 言归正传,对java有了解的同学基本上都体验过JDB ...
随机推荐
- shell编程之存储读写测试实战脚本
Shell编程是一种在命令行环境中编写程序的技术,常用于Linux和Unix系统.它主要使用Shell脚本语言来编写程序.Shell编程常用于系统管理.自动化任务.批处理等领域. 常用的Shell脚本 ...
- [ABC213E] Stronger Takahashi
2023-01-17 题目 题目传送门 翻译 难度&重要性(1~10):4 题目来源 AtCoder 题目算法 bfs 解题思路 首先,这道题的问题是从家到鱼市摧毁障碍物的最少次数.我们很容易 ...
- 【Ubuntu】Ubuntu 配置记录
目录 系统文件夹改回英文 Ubuntu 镜像 pypi 镜像 临时使用 设为默认 Doxygen + Graphviz 分析代码并画图 Graphviz 安装 Doxygen 安装 配置 运行 系统文 ...
- 关于ChatGPT的一些闲扯淡(1)
这篇写的有点迟了,前者子ChatGPT正火的时候,懒病发作一直拖延.今天对ChatGPT做一个简单的讨论,也是把学习的心得和大家分享一下. 首先什么是GPT,英文全称是Generative Pretr ...
- 1.12 进程注入ShellCode套接字
在笔者前几篇文章中我们一直在探讨如何利用Metasploit这个渗透工具生成ShellCode以及如何将ShellCode注入到特定进程内,本章我们将自己实现一个正向ShellCodeShell,当进 ...
- 关于API数据接口获取商品的数据的说明
获取商品数据已经成为许多应用程序的重要组成部分.为了实现这一目标,许多公司和技术开发者使用API数据接口来获取相关数据.本文将详细介绍如何使用API数据接口获取商品数据,并使用Python作为编程 ...
- MySQL实战实战系列 04 深入浅出索引(上)
提到数据库索引,我想你并不陌生,在日常工作中会经常接触到.比如某一个 SQL 查询比较慢,分析完原因之后,你可能就会说"给某个字段加个索引吧"之类的解决方案.但到底什么是索引,索引 ...
- LeetCode 周赛上分之旅 #49 再探内向基环树
️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...
- Berkeley
2019年Berkeley预测Serverless将取代Serverful计算,成为云计算的计算新范式.Serverless为应用程序开发提供了一种全新的系统架构,其凭借着弹性伸缩省事省心,按需付费更 ...
- 记一次Redis Cluster Pipeline导致的死锁问题
作者:vivo 互联网服务器团队- Li Gang 本文介绍了一次排查Dubbo线程池耗尽问题的过程.通过查看Dubbo线程状态.分析Jedis连接池获取连接的源码.排查死锁条件等方面,最终确认是因为 ...