本文主要介紹在mybatis中如何在sql語句中傳遞引數
一. #{ } 和 ${ }
1. #{ } 和 ${ }的區別
#{ }是預編譯處理 ==> PreparedStatement
${ }是字串替換 ==> Statement
mybatis在處理 #{ } 時,會將sql中的 # { } 替換為?號,呼叫PreparedStatement的set()方法來賦值;
mybatis在處理 ${ } 時,會將 ${ } 替換成變數的值。
因此 #{ }可以防止sql注入,而 ${ }不可以防止sql注入。
注意:在使用 ${ }時,需要在 ${ } 打上 ' ',即 ' ${ } '。
2. #{ } 和 ${ } 的使用
2.1 當查詢條件只有一個時
首先看看UserMapper介面的定義:
public interface UserMapper { // 按照姓名查詢資料 User getUserByName(String username); }
1)在UserMapper.xml檔案中,使用 #{ } 傳遞引數
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--User getUserByName()--> <select id="getUserByName" resultType="User"> <!--select * from t_user where username = #{username}--> select * from t_user where username = #{param2} </select> </mapper>
測試test
// 按姓名查詢資料 @Test public void selectUserByName(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User jack = mapper.getUserByName("jack"); System.out.println(jack); SqlSessionUtils.closeSqlSession(); }
執行結果
xml檔案中的sql語句
select * from t_user where username = #{param2}
上述的sql語句解析為:
select * from t_user where username = 'jack'
注意:當mapper介面的查詢方法的形參列表只有一個的情況下, #{ }中的引數可以隨便書寫
2)在在UserMapper.xml檔案中,使用 ${ } 傳遞引數
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--User getUserByName()--> <select id="getUserByName" resultType="User"> select * from t_user where username = '${param2}' </select> </mapper>
注意:在使用 ${ }時,需要在 ${ } 打上 ' ',即 ' ${ } '。
測試test
// 按姓名查詢資料 @Test public void selectUserByName(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User jack = mapper.getUserByName("jack"); System.out.println(jack); SqlSessionUtils.closeSqlSession(); }
執行結果
xml檔案中的sql語句
select * from t_user where username = '${param2}'
上述的sql語句解析為
select * from t_user where username = 'jack'
由此可見,${ } 並沒有預編譯處理,但是 #{ } 有預編譯處理,顯示出 #{ } 的安全性 【防止sql注入】
注意:當mapper介面查詢方法的形參列表只有一個的時候,${ }中的引數可以隨便書寫
2.2 當查詢條件不只有一個時
以使用 #{ } 傳遞引數 舉例
情況1:若UserMapper介面宣告如下
public interface UserMapper { // 按照姓名和密碼查詢 User checkLogin(String username,String password); }
則 在xml檔案中使用args0,args1,param1,param2...作為 #{ }的引數
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--User checkLogin(String username,String password)--> <select id="checkLogin" resultType="User" > <!--Available parameters are [arg1, arg0, param1, param2]--> select * from t_user where username = #{param1} and password = #{param2} </select> </mapper>
如果不用args0,args1,param1,param2...,則會報如下異常
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'param' not found. Available parameters are [arg1, arg0, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'param' not found. Available parameters are [arg1, arg0, param1, param2]
情況2:若UserMapper介面宣告如下
public interface UserMapper { // 引數map查詢資料 User checkLoginByMap(Map<String,Object> map); }
則 在UserMapper介面的checkLogin()中傳入Map型別,達到自定義 #{ } 中引數的名稱
xml檔案宣告如下,#{ } 傳入的引數即Map中K鍵
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--User checkLoginByMap(Map<String,Object> map)--> <select id="checkLoginByMap" resultType="User" > select * from t_user where username = #{username} and password = #{password} </select> </mapper>
測試test
@Test public void selectByMap(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap<>(); map.put("username","jack"); map.put("password","tom12345"); User user = mapper.checkLoginByMap(map); System.out.println(user); SqlSessionUtils.closeSqlSession(); System.out.println(sqlSession); }
注意:在這種情況下,#{ } 的引數必須是形參Map的 key 鍵。
情況3:UserMapper介面宣告如下
public interface UserMapper { // 引數為User新增資料 int insertByUser(User user); }
則 在xml檔案宣告如下,#{ } 的引數即為User類的屬性
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--int insertUser(User user)--> <insert id="insertByUser" > insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email}) </insert> </mapper>
測試test
// 測試使用物件作為引數,新增使用者 @Test public void testInsertByUser(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(null, "hsp", "hsp12345", 25, "男", "hsp123@qq.com"); int i = mapper.insertByUser(user); System.out.println(i); sqlSession.close(); }
情況4:UserMapper介面宣告如下
public interface UserMapper { // @Param作為引數 User checkLoginByParam(@Param("user") String username,@Param("pwd") String password); }
xml檔案宣告如下,使用@Param註解,指明在 #{ } 中傳入的引數,更加方便
<mapper namespace="com.hspedu.mapper.UserMapper"> <!--User checkLoginByParam(@Param("user") String username,@Param("pwd") String password)--> <select id="checkLoginByParam" resultType="User" > select * from t_user where username = #{user} and password = #{pwd} </select> </mapper>
測試test
@Test // 透過註解@Param傳遞引數 public void testByParam(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.checkLoginByParam("jack", "tom12345"); System.out.println(user); sqlSession.close(); }
二. 總結
在 #{ } 中:增加,修改使用情況3的處理方式,傳入User實體類物件
查詢,使用情況4的處理方式,在mapper介面定義的方法的形參列表中 新增 @Param註解。