事情的發展是這樣的:
因為一個需求,需要在java中拼接出一個完整的sql語句,然后將整條sql語句傳遞給mybatis執行。
mapper.java是這樣的:
int insertMaster(WorksheetMasterSQLBean masterBean);
這個對象是:
public class WorksheetMasterSQLBean { private Long id; private String masterInsertSql;
【就是用
masterInsertSql 字段裝了一下SQL,因為要在insert執行后返回自增ID的緣故,所以把SQL裝在一個對象的屬性中。主要就是想用一個bean的id取接收一下自增id.
無所謂啦,往下看】【mybatis的insert返回自增id】
mapper.xml是這樣的:
【把sql放進insert標簽中,執行】
<insert id="insertMaster" parameterType="com.lqjava.daywork.api.beans.WorksheetMasterSQLBean" useGeneratedKeys="true" keyProperty="id"> #{masterInsertSql} </insert>
SQL語句是:
【這就是在java中直接拼接好的sql語句】
INSERT INTO worksheet_data_14 (create_by,create_date,update_by,update_date,`input-number_0`) VALUES (1,'2019-05-15 12:44:45',1,'2019-05-15 12:44:45','坦桑尼亞' )
報錯:
【媽的,報錯了】
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''INSERT INTO
原因:
1.到了這里,就思考這個問題。
我傳入的參數,也就是String類型的sql語句,明明就是上面那個,為什么執行完了會報錯。而且錯誤提示,就是在
''INSERT INTO
這個地方?
懷疑是不是在java中sql拼接的時候,自己多搞出來幾個單引號在前面呀【或者空格之類的】
2.仔細的debug了幾次程序,發現,java中拼接出來的sql語句完全沒有任何問題。
既沒有加單引號,又沒有前后空格,也沒有使用關鍵字這一說。
那問題只能在將 sql送進mybatis之后,發生的問題了。
3.這里就說到了mybatis的$和#的區別
首先:
mybatis拼接sql時候,使用${參數} 和 #{參數} 都可以接受參數
第二:
例如:age = 1
select * from user where age = #{age};
select * from user where age = ${age};
如果使用${參數},那就是將參數原原本本的進行字符串的替換,不會做任何過多的處理。
看一下${}對上面的預編譯的結果為
select * from user where age = 1;
如果使用#{參數},則會在預編譯階段生成占位符?,實際值的替換是在DBMS中進行的。
看一下#{}對上面的預編譯的結果為
select * from user where age = ?;
4.那看到了$和#的區別,為什么兩個都可以在mybatis中使用?各自的優勢何在?
1》#{},預編譯生成占位符?,實際的參數值替換在DBMS中,根據參數類型,是否添加''單引號。
第一個優勢:
省時省力。那預編譯的語句,會被緩存下來,下次相同的語句執行,不用編譯,直接就可以拿到數據庫操作,直接在數據庫中進行參數替換即可。省時省力。
第二個優勢:
防止SQL注入。如果像我上面的使用情況,我給占位符的地方傳入的並不是一個值,而是一個;delete的刪除語句,那直接傳入數據庫中,有了占位符替換的過程,會自動給string類型的加上''單引號在前后,這樣就出現了上面我的錯誤。執行不了。
2》${},直接進行字符串的替換。
那按上面那么說,${}就完全沒有優勢可言了么?
不是的,就像上面的錯誤一樣,這個時候就需要${}出馬,才能直接將完整的sql語句替換。不會添加任何的''在前后。
所以,像是如果mybatis中寫了sql,但是表名是動態的,則需要${}。因為表名是不需要加''在前后的。
5.對於mybatis中#和$的總結
#{}是占位符號
${}是sql拼接符號
解決方案:
替換mapper.xml中的#為$,即可解決問題:
<insert id="insertMaster" parameterType="com.lqjava.daywork.api.beans.WorksheetMasterSQLBean" useGeneratedKeys="true" keyProperty="id"> ${masterInsertSql} </insert>