Mybatis动态指定表名、列名,如何防⽌SQL注⼊?以下的代码,操作的是MySQL数据库
⽅式⼀
因为表名⽆法通过 CONCAT() 函数进⾏拼接,所以只能通过 ${} 直接将表名的字符串替换。
<select id="selectUnionALL" resultType="Dept">
SELECT * FROM ${tableName} WHERE deptno = #{deptno}
</select>
但是会存在SQL的注⼊,⽐如:tableName = dept_01; delete from dept_01; 就会删除所有的数据。
解决⽅式:通过代码去判断传⼊的参数是否包含 delete、 等危险操作。
⽅式⼆
假设存在数据库中存在 dept_01,dept_02, 这样命名的表,那么怎么做呢?
可以通过存储过程去解决动态指定表名的问题。
1)创建存储过程
DROP PROCEDURE IF EXISTS getName;    -- 如果⼀创建存储过程则删除
DELIMITER $$ -- 定义结束字符,可以任意
-- 创建名称为getName的存储过程,需要传⼊的参数:tableName表名,deptno条件
CREATE PROCEDURE getName(IN tableName VARCHAR(100), IN deptno INT)
BEGIN
DECLARE tn VARCHAR(10);    -- 创建变量保存表名
set tn =
(    -- 查询MySQL中所有的表,然后根据表所在的数据库和表的后缀名称获取到对应的表名
select table_name
from information_schema.TABLES
where table_schema='db03'
AND table_name LIKE CONCAT('dept_', '%')
AND table_name LIKE CONCAT('%', tableName)
);
-- 再拼接查询语句
set@sqlStr= CONCAT("SELECT*FROM ", tn," WHERE deptno ='", deptno, "'");
PREPARE sqlStr FROM@sqlStr;
EXECUTE sqlStr;    -- 执⾏
END $$
-- 传⼊参数:表名的后缀部门id
CALL getName('02', 5);    -- 测试
测试结果,这样就不存在注⼊问题,因为表名被作为了条件。
2)接⼝编写
// Controller层
@GetMapping("selectUnionALL/db03")
@ResponseBody
public List<Dept> selectUnionALL() {
Dept dept = new Dept();
dept.setDeptno(5L);
dept.setTableName("02");
return deptService.selectUnionALL(dept);
}
// service层
public List<Dept> selectUnionALL(Dept dept) {
return deptMapper.selectUnionALL(dept);
}
// mapper层
List<Dept> selectUnionALL(Dept dept);
3)l 调⽤
<!-- statementType: 需要设置为 CALLABLE -->
tabletable<select id="selectUnionALL" resultType="Dept" statementType="CALLABLE">    CALL getName(#{tableName}, #{deptno});
</select>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。