JDBC常见异常(10)—预编译模式下占位符动态排序字段失效

2024-06-01 11:36

本文主要是介绍JDBC常见异常(10)—预编译模式下占位符动态排序字段失效,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

场景需求

需要根据不同的列进行对应的排序操作,实现动态列名排序 类似🐟动态查询或更新

但是JDBC预编译模式下占位符的排序字段失效

SQL语句

分页查询

select * from (select t.*, rownum rn from(select * from emp order by empno desc) t where rownum <= 5)    where rn > 0;

指定列排序失效

select * from (select t.*, rownum rn from(select * from emp order by ?  desc) t where rownum <= 5)    where rn > 0;

临时解决字符串拼接

  • SQL注入问题
select * from (select t.*, rownum rn from(select * from emp order by "+ empno  +  "  desc) t where rownum <= 5)    where rn > 0;

预编译注入排序列名排序失效

PreparedStatement执行SQL时,如果order by之后的排序字段使用占位符,通过setString设置值的话,会导致排序失效

// 4 SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
PreparedStatement pstmt = conn.prepareStatement(sql);// 如果SQL有?号  参数需要注入
pstmt.setString(1, sortColumnName); // 1 代表 第一个?  从1开始   以此类推

源码

/*** An object that represents a precompiled SQL statement.* <P>A SQL statement is precompiled and stored in a* {@code PreparedStatement} object. This object can then be used to* efficiently execute this statement multiple times.** <P><B>Note:</B> The setter methods ({@code setShort}, {@code setString},* and so on) for setting IN parameter values* must specify types that are compatible with the defined SQL type of* the input parameter. For instance, if the IN parameter has SQL type* {@code INTEGER}, then the method {@code setInt} should be used.** <p>If arbitrary parameter type conversions are required, the method* {@code setObject} should be used with a target SQL type.* <P>* In the following example of setting a parameter, {@code con} represents* an active connection:* <pre>{@code*   BigDecimal sal = new BigDecimal("153833.00");*   PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES*                                     SET SALARY = ? WHERE ID = ?");*   pstmt.setBigDecimal(1, sal);*   pstmt.setInt(2, 110592);* }</pre>** @see Connection#prepareStatement* @see ResultSet* @since 1.1*/
public interface PreparedStatement extends Statement {/*** Sets the designated parameter to the given Java {@code String} value.* The driver converts this* to an SQL {@code VARCHAR} or {@code LONGVARCHAR} value* (depending on the argument's* size relative to the driver's limits on {@code VARCHAR} values)* when it sends it to the database.** @param parameterIndex the first parameter is 1, the second is 2, ...* @param x the parameter value* @throws SQLException if parameterIndex does not correspond to a parameter* marker in the SQL statement; if a database access error occurs or* this method is called on a closed {@code PreparedStatement}*/void setString(int parameterIndex, String x) throws SQLException;... 
}

核心解释

  • 将指定的参数设置为给定的Java{@code String}值。
  • 驱动程序转换此转换为SQL{@code VARCHAR}或{@code LONGVARCHAR}值

原因

PreparedStatement用占位符防止SQL注入的原理是,在为占位符设置值时,会将值转为字符串,然后转义,再将值放入反引号中,放置在占位符的位置上。

因此,当排序字段使用占位符后,原来的排序语句 order by empno(假设排序字段是empno),在实际执行时变成了 order by empno,根据字段排序变成了根据字符串常量值empno排序,导致排序失效,甚至任意的注入数值都不影响前面的查询结果

情况一

使用预编译的数据库操作对象在order by后面设置占位符,再通过pstmt.setString()方法填入参数会导致排序失败

情况二

使用mybatis的时候,在mapper sql映射.xml文件中,在order by 后面使用 #{参数名} 依然会导致排序失败,因为mybatis #{} 使用的是PrepareStatement

解决办法

  • #{}方式传参数只能处理值参数 不能传递表名,字段等参数
  • ${}字符串替换,可以动态处理表名,字段参数

#{}改成${}, #{}是预编译,相当于PrepareStatement;${}是普通字符串的拼接,相当于Statement

但是必须注意SQL注入的风险,对参数做好校验处理

这篇关于JDBC常见异常(10)—预编译模式下占位符动态排序字段失效的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020891

相关文章

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Java 方法重载Overload常见误区及注意事项

《Java方法重载Overload常见误区及注意事项》Java方法重载允许同一类中同名方法通过参数类型、数量、顺序差异实现功能扩展,提升代码灵活性,核心条件为参数列表不同,不涉及返回类型、访问修饰符... 目录Java 方法重载(Overload)详解一、方法重载的核心条件二、构成方法重载的具体情况三、不构

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

Python中反转字符串的常见方法小结

《Python中反转字符串的常见方法小结》在Python中,字符串对象没有内置的反转方法,然而,在实际开发中,我们经常会遇到需要反转字符串的场景,比如处理回文字符串、文本加密等,因此,掌握如何在Pyt... 目录python中反转字符串的方法技术背景实现步骤1. 使用切片2. 使用 reversed() 函

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操