MyBatis的使用三(在sql語句中傳值)

2023-02-03 06:00:32

本文主要介紹在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, "男", "[email protected]");
        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註解。