Statement与PreparedStatement的区别理解记录

2023-05-16

一、PreparedStatement性能高于Statement(PreparedStatement)属于预编译(缓存),那怎么预编译的呢,源码对比。

Statement创建:只是通过构造方法创建了一个StatementImpl对象,之后通过StatementImpl解析SQL,解析sql根据不同的驱动解析sql,并且需要连接数据库,才能确定表,所以这里一会存在一次网络连接(其实效率主要是这次网路开销),没有使用缓存。

public StatementImpl(MySQLConnection c, String catalog) throws SQLException {
		if ((c == null) || c.isClosed()) {
			throw SQLError.createSQLException(
					Messages.getString("Statement.0"), //$NON-NLS-1$
					SQLError.SQL_STATE_CONNECTION_NOT_OPEN, null); //$NON-NLS-1$ //$NON-NLS-2$
		}

		this.connection = c;
		this.connectionId = this.connection.getId();
		this.exceptionInterceptor = this.connection
				.getExceptionInterceptor();

		this.currentCatalog = catalog;
		this.pedantic = this.connection.getPedantic();
		this.continueBatchOnError = this.connection.getContinueBatchOnError();
		this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode();
		
		if (!this.connection.getDontTrackOpenResources()) {
			this.connection.registerStatement(this);
		}

		//
		// Adjust, if we know it
		//

		if (this.connection != null) {
			this.maxFieldSize = this.connection.getMaxAllowedPacket();

			int defaultFetchSize = this.connection.getDefaultFetchSize();

			if (defaultFetchSize != 0) {
				setFetchSize(defaultFetchSize);
			}
			
			if (this.connection.getUseUnicode()) {
				this.charEncoding = this.connection.getEncoding();

				this.charConverter = this.connection.getCharsetConverter(this.charEncoding);
			}
			
			

			boolean profiling = this.connection.getProfileSql()
					|| this.connection.getUseUsageAdvisor() || this.connection.getLogSlowQueries();

			if (this.connection.getAutoGenerateTestcaseScript() || profiling) {
				this.statementId = statementCounter++;
			}

			if (profiling) {
				this.pointOfOrigin = LogUtils.findCallingClassAndMethod(new Throwable());
				this.profileSQL = this.connection.getProfileSql();
				this.useUsageAdvisor = this.connection.getUseUsageAdvisor();
				this.eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
			}

			int maxRowsConn = this.connection.getMaxRows();

			if (maxRowsConn != -1) {
				setMaxRows(maxRowsConn);
			}
			
			this.holdResultsOpenOverClose = this.connection.getHoldResultsOpenOverStatementClose();
		}
		
		version5013OrNewer = this.connection.versionMeetsMinimum(5, 0, 13);
	}

PreparedStatement的创建:判断是否存在缓存,如果不存在缓存则创建,并在创建成功之后关闭流的时候判断PreparedStatement是否存在,如果存在,则放入缓存,从而保证sql的解析过程只有一次。

public java.sql.PreparedStatement prepareStatement(String sql,
			int resultSetType, int resultSetConcurrency) throws SQLException {
		synchronized (getConnectionMutex()) {
			checkClosed();
	
			//
			// FIXME: Create warnings if can't create results of the given
			// type or concurrency
			//
			PreparedStatement pStmt = null;
			
			boolean canServerPrepare = true;
			
			String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql;
			
			if (this.useServerPreparedStmts && getEmulateUnsupportedPstmts()) {
				canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
			}
			
			if (this.useServerPreparedStmts && canServerPrepare) {
                //是否存在缓存,如果存在缓存则取缓存的对象,不存在则创建。
				if (this.getCachePreparedStatements()) {
					synchronized (this.serverSideStatementCache) {
						pStmt = (com.mysql.jdbc.ServerPreparedStatement)this.serverSideStatementCache.remove(sql);
						
						if (pStmt != null) {
							((com.mysql.jdbc.ServerPreparedStatement)pStmt).setClosed(false);
							pStmt.clearParameters();
						}
	
						if (pStmt == null) {
							try {
								pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
										this.database, resultSetType, resultSetConcurrency);
								if (sql.length() < getPreparedStatementCacheSqlLimit()) {
									((com.mysql.jdbc.ServerPreparedStatement)pStmt).isCached = true;
								}
								
								pStmt.setResultSetType(resultSetType);
								pStmt.setResultSetConcurrency(resultSetConcurrency);
							} catch (SQLException sqlEx) {
								// Punt, if necessary
								if (getEmulateUnsupportedPstmts()) {
									pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
									
									if (sql.length() < getPreparedStatementCacheSqlLimit()) {
										this.serverSideStatementCheckCache.put(sql, Boolean.FALSE);
									}
								} else {
									throw sqlEx;
								}
							}
						}
					}
				} else {
					try {
						pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
								this.database, resultSetType, resultSetConcurrency);
						
						pStmt.setResultSetType(resultSetType);
						pStmt.setResultSetConcurrency(resultSetConcurrency);
					} catch (SQLException sqlEx) {
						// Punt, if necessary
						if (getEmulateUnsupportedPstmts()) {
							pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
						} else {
							throw sqlEx;
						}
					}
				}
			} else {
				pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
			}
			
			return pStmt;
		}
	}

二、为什么PreparedStatement能防止大部分SQL注入。

原始SQL为:

SELECT * FROM USER WHERE ID = ?;

SELECT * FROM USER WHERE ID = 1;

当用户传入的参数是 1 OR 1=1 时,执行的sql将分别变成,1报错,因为1 OR 1=1转换不了数字,2变成

SELECT * FROM USER WHERE ID = 1 OR 1 = 1;

则查回所有数据信息。

原始SQL为:

SELECT * FROM USER WHERE ID = ?;

SELECT * FROM USER WHERE ID = '1';

当用户传入的参数是 1 OR 1=1 时,执行的sql将分别变成

SELECT * FROM USER WHERE ID = '1 OR 1 = 1';

SELECT * FROM USER WHERE ID = 1 OR 1 = 1;

一个查不回任何数据信息,一个查回所有。

但假如我们对预编译的SQL使用的$,而非#,效果如何

原始SQL为:

SELECT * FROM USER WHERE ID = ?;

SELECT * FROM USER WHERE ID = 1;

结果变成

SELECT * FROM USER WHERE ID = 1 OR 1 = 1;

SELECT * FROM USER WHERE ID = 1 OR 1 = 1;

都会查回所有,这种情况就不能防止SQL注入,所有${}可能带来SQL注入的风险,且不能通过PreparedStatement规避。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Statement与PreparedStatement的区别理解记录 的相关文章

  • golang数据类型转换(int/float/string/interface/[]byte)

    文章目录 1 int和float转换1 1 int 61 61 gt float32 641 2 float64 32 61 61 gt int 2 字串和数字的转换 xff08 strconv xff09 2 1 string 61 61
  • yy欢聚时代软件测试笔试题

    1 xff0c 10111001对应的八进制 xff0c 十六进制和十进制 2 xff0c 常见的数据库有那些 xff1f 3 xff0c 常见的协议有哪些 xff1f 4 xff0c 代码运行结果 xff0c c 43 43 题目 xff
  • 黑苹果安装教程,配EFI引导文件+软件!

    买不起苹果电脑 xff0c 那最好的办法 xff0c 就是把我们的普通电脑装成苹果系统 不过安装macos系统 xff0c 没有安装windows那么简单 xff0c 步骤比较复杂 对于新手来说不知道如何下手 xff1f 这里我就来分享一下
  • 用单链表实现的内存管理

    http blog csdn net csynyk article details 2861979 在C语言论坛中看了dgarc发表的一个贴子后 xff0c 按要求写了一段代码 xff0c 可以实现内存分配的管理 xff0c 避免内存泄漏
  • tomcat端口冲突问题

    问题 xff1a 在本地启tomcat xff0c 报错 严重 StandardServer await create 8080 java net BindException Address already in use JVM Bind
  • 云计算的三大服务模式

    根据NIST的权威定义 xff0c 云计算有SPI xff0c 即SaaS PaaS和IaaS三大服务模式 这是目前被业界最广 泛认同的划分 PaaS和IaaS源于SaaS理念 PaaS和IaaS可以直接通过SOA Web Services
  • 使用DISM修复系统

    在win10系统中 xff0c 当系统出现文件受损或丢失后 xff0c 可以使用DISM工具进行联机修复 xff1a 1 使用管理员运行CMD xff1a DISM Online Cleanup image RestoreHealth 命令
  • 解决火狐浏览器提示连接不安全或证书错误的问题

    问题 xff1a 在地址栏输入 xff1a about config 接受风险并继续 xff0c 然后在方框中输入 xff1a security enterprise roots enabled 将false切换为true 测试
  • MacOS没有管理员账号的解决方法

    MacOS没有管理员账号的解决方法 参考文档 xff1a https www jianshu com p 7682230edfba 应用场景 xff1a 员工的Mac内只有一个普通用户 xff0c 没有管理员用户 解决方案 xff1a 1
  • ubuntu18设置不要进入休眠,省去输入密码的麻烦

    1合盖不休眠 Ctrl Alt T 组合键打开终端 xff1b 然后修改配置文件 etc systemd logind conf vim etc systemd logind conf 打开文件后修改下面这行 xff1a HandleLid
  • HP BIOS降级

    应用场景 xff1a 员工电脑型号为HP 280 Pro G2 MT xff0c 为员工加装固态硬盘 xff08 硬盘型号 xff1a Samsung V NAND 860 EVO xff09 时 xff0c bios版本过高会导致电脑在开
  • systemd服务

    Systemd 的简介和特点 Systemd 是 Linux 系统中的初始化系统 xff08 init xff09 xff0c 它主要的设计目标是克服sysvinit 固有的缺点 xff0c 提高系统的启动速度 systemd和ubuntu
  • 重定向

    重定向简介 计算机最基础的功能是可以提供输入输出操作 对于Linux系统来说 xff0c 通常以键盘为默认输入设备 xff0c 又称标准输入设备 xff1b 以显示器为默认的输出设备 xff0c 又称标准输出设备 所谓重定向 xff0c 就
  • Canon imageRUNNER 2525i打印机驱动通过IP地址进行安装

    环境 打印机IP xff1a 192 168 140 251 本机IP xff1a 192 168 141 210 操作 一 下载驱动 方法一 xff1a 佳能ir 2525i驱动下载地址 xff1a https pdisp01 c wss
  • 防火墙firewalld

    RHEL7中有几种防火墙共存 xff1a firewalld iptables ebtables等 基于iptables的防火墙默认不启动 xff0c 但仍然可以继续使用 RHEL7默认使用firewalld作为防火墙 xff0c 管理工具
  • redis报错Unrecoverable error: corrupted cluster config file.

    系统因为做物理硬件迁移硬重启了一次 在启动redis时出现了一下问题 xff1a 启动脚本 xff1a 运行启动脚本 xff1a 提示正在运行但是没有进程出现 在redis conf中将daemonize yes设置为daemonize n
  • vcenter开机报错activating swap-devices in /etc/fstab

    问题 xff1a 昨天IDC机房一台存储断电了 xff0c 恰巧vcenter在这台存储上 xff0c 重启存储后再重启vcenter报了以下错误 xff1a 参考文档 xff1a https www virtualizestuff com
  • IDEA Git 分支branch操作,新建和合并

    简单记录IDEA中Git分支操作 1 xff1a 创建分支 右下角new branch创建分支 创建完成查看右下角当前分支情况 创建一个该分支的MD文件信息 xff0c 进行提交 这样一个分支就创建完成 xff0c 然后merge分支 xf
  • KVM 介绍(1):简介及安装

    转载地址 xff1a http www cnblogs com sammyliu p 4543110 html KVM 介绍 xff08 1 xff09 xff1a 简介及安装 学习 KVM 的系列文章 xff1a xff08 1 xff0
  • 个人面试经验总结

    1 xff0c 海投 2 xff0c 一定要强调自己能留到该地 xff08 这个城市 这个公司 xff09 发展 3 xff0c 简历上出现的技能和项目面试前一天一定要复习 xff0c 因为面试官大部分问题会以简历为主 4 xff0c 要有

随机推荐

  • Java学习笔记4(设计模式、接口)

    设计模式 建造者模式 在类中 xff0c 定义一个静态内部类作为 外部类的 建造者在建造者类中 xff0c 提供多个 方法用来完成 外部类 对象的属性赋值在建造者类中 xff0c 提供一个 build 用来返回一个外部类的对象在类中 xff
  • R语言单因素/多因素 Logistic回归

    变量因子的转换 gt 单因素logistic回归 gt 多因素logistic回归 https mp weixin qq com s NowePGv6DF9 dF4blSyzVQ 两个模型的比较 构造测试集 xff0c 预测概率 xff0c
  • 那一年读过的技术经典书

    转载请注明 xff1a http blog csdn net xinzhangyanxiang article details 10199757 大学刚毕业 xff0c 总结起来读过的书并不算多 xff0c 而且主要集中在大四的时期读的 x
  • Bert: 双向预训练+微调

    最近要开始使用Transformer去做一些事情了 xff0c 特地把与此相关的知识点记录下来 xff0c 构建相关的 完整的知识结构体系 以下是要写的文章 xff0c 文章大部分都发布在公众号 雨石记 上 xff0c 欢迎关注公众号获取最
  • Federated Learning: 问题与优化算法

    工作原因 xff0c 听到和使用Federated Learning框架很多 xff0c 但是对框架内的算法和架构了解不够细致 xff0c 特读论文以记之 这个系列计划要写的文章包括 xff1a Federated Learning 问题与
  • DIN: 阿里点击率预估之深度兴趣网络

    广告推荐算法系列文章 xff1a 莫比乌斯 百度的下一代query ad匹配算法百度凤巢分布式层次GPU参数服务器架构DIN 阿里点击率预估之深度兴趣网络DIEN 阿里点击率预估之深度兴趣进化网络 本文的知识点来源于参考文献 1 xff0c
  • DIEN: 阿里点击率预估之深度兴趣进化网络

    广告推荐算法系列文章 xff1a 莫比乌斯 百度的下一代query ad匹配算法百度凤巢分布式层次GPU参数服务器架构DIN 阿里点击率预估之深度兴趣网络基于Delaunay图的快速最大内积搜索算法DIEN 阿里点击率预估之深度兴趣进化网络
  • 概率矩阵分解模型 PMF

    本文是论文 一种结合推荐对象间关联关系的社会化推荐算法 的笔记 xff08 上 xff09 因为对其中的概率矩阵分解 Probabilistic Matrix Factorization PMF 不够了解 xff0c 因而我先去脑补了PMF
  • 卷积神经网络

    卷积神经网络 转载请注明 xff1a http blog csdn net stdcoutzyx article details 41596663 自今年七月份以来 xff0c 一直在实验室负责卷积神经网络 xff08 Convolutio
  • DeepID人脸识别算法之三代

    DeepID人脸识别算法之三代 转载请注明 xff1a http blog csdn net stdcoutzyx article details 42091205 DeepID xff0c 目前最强人脸识别算法 xff0c 已经三代 如今
  • 理解dropout

    理解dropout 开篇明义 xff0c dropout是指在深度学习网络的训练过程中 xff0c 对于神经网络单元 xff0c 按照一定的概率将其暂时从网络中丢弃 注意是暂时 xff0c 对于随机梯度下降来说 xff0c 由于是随机丢弃
  • MYSQL— perror 错误码详情

    root 64 localhost cat test nothread py import paramiko import threading import os def ssh2 ip username passwd cmd file p
  • 深度卷积对抗生成网络(DCGAN)

    本文是参考文献 1 的论文笔记 卷积神经网络在有监督学习中的各项任务上都有很好的表现 xff0c 但在无监督学习领域 xff0c 却比较少 本文介绍的算法将有监督学习中的CNN和无监督学习中的GAN结合到了一起 在非CNN条件下 xff0c
  • 看图说话——CNN和LSTM的联合应用

    看图说话是深度学习波及的领域之一 其基本思想是利用卷积神经网络来做图像的特征提取 xff0c 利用LSTM来生成描述 但这算是深度学习中热门的两大模型为数不多的联合应用了 本文是参考文献 1 的笔记 xff0c 论文是比较早的论文 xff0
  • 机器学习经典书籍小结

    机器学习经典书籍小结 转载本博客请注明链接 xff1a http blog csdn net xinzhangyanxiang article details 9069045 博客第一篇文章 1 是转载的 xff0c 也算是开始写博客不经意
  • (一)Tensorflow图像数据转化TFRecord数据格式

    1 TFRecord数据格式 Tensorflow提供的TFRecord文件数据是通过tf train Example Protocol Buffer的格式存储的 数据格式 message Example Features features
  • 【26】Gson原理

    xff08 1 xff09 一个人只要自己不放弃自己 xff0c 整个世界也不会放弃你 xff08 2 xff09 天生我才必有大用 xff08 3 xff09 不能忍受学习之苦就一定要忍受生活之苦 xff0c 这是多么痛苦而深刻的领悟 x
  • Failed to load plugin html: Cannot find module 'eslint-plugin-html'

    npm install save dev eslint plugin html
  • 在 Windows 中启用自动登录功能

    在 Windows 中启用自动登录功能 本文介绍了如何通过将密码和其他相关信息存储在注册表数据库中以配置 Windows 自动执行登录过程 通过使用此功能 xff0c 其他用户可以启动您的计算机并使用您建立的帐户自动登录 为了方便起见 xf
  • Statement与PreparedStatement的区别理解记录

    一 PreparedStatement性能高于Statement xff08 PreparedStatement xff09 属于预编译 xff08 缓存 xff09 xff0c 那怎么预编译的呢 xff0c 源码对比 Statement创