以下的代碼,操作的是MySQL數據庫
方式一
因為表名無法通過 CONCAT() 函數進行拼接,所以只能通過 ${} 直接將表名的字符串替換。
<select id="selectUnionALL" resultType="Dept"> SELECT * FROM ${tableName} WHERE deptno = #{deptno} </select>
但是會存在SQL的注入,比如:tableName = dept_01; delete from dept_01; 就會刪除所有的數據。
解決方式:通過代碼去判斷傳入的參數是否包含 delete、drop... 等危險操作。
方式二
假設存在數據庫中存在 dept_01,dept_02,dept_03..... 這樣命名的表,那么怎么做呢?
可以通過存儲過程去解決動態指定表名的問題。
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)mapper.xml 調用
<!-- statementType: 需要設置為 CALLABLE --> <select id="selectUnionALL" resultType="Dept" statementType="CALLABLE"> CALL getName(#{tableName}, #{deptno}); </select>