android网站开发视频,俄罗斯乌克兰伤亡人数,软件应用商店排行榜,海外网站营销场景需求
需要根据不同的列进行对应的排序操作#xff0c;实现动态列名排序 类似#x1f41f;动态查询或更新
但是JDBC预编译模式下占位符的排序字段失效
SQL语句
分页查询
select * from (select t.*, rownum rn from(select * from emp order by empno desc) t where …场景需求
需要根据不同的列进行对应的排序操作实现动态列名排序 类似动态查询或更新
但是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.* PA SQL statement is precompiled and stored in a* {code PreparedStatement} object. This object can then be used to* efficiently execute this statement multiple times.** PBNote:/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.** pIf 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 arguments* size relative to the drivers 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;...
}核心解释
将指定的参数设置为给定的Javacode 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注入的风险对参数做好校验处理