MyBatis 引數處理

LZC發表於2020-02-18

引數處理

單個引數

透過#{引數名}取出引數值

介面定義如下

public User getUserByUserName(String userName);

介面對應的 Mapper.xml 定義如下所示

<select id="getUserByUserName"
        parameterType="String"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where username = #{username}
</select>

多個引數

MyBatis會做特殊處理,會將你的多個引數封裝成一個Map,keyparam1, param2,..., paramN,value為 value1,value2,...valueN,可以透過#{param1}來獲取value1的值,#{paramN}來獲取valueN的值。value1,value2,...valueN就是我們透過方法傳遞過來的值。

介面定義如下

public User getUserByIdAndUserName(Integer id, String username);

介面對應的 Mapper.xml 定義如下所示。 兩個引數分別是 Integer 型別和 String 型別,型別不一致,此時 parameterType 可以省略 。

<select id="getUserByIdAndUserName"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where id = #{param1}
    and username = #{param2}
</select>

這裡需要注意的是透過 #{param1} 和 #{param2} 來對映兩個引數,以此類推,如果有第 3 個引數,則使用 #{param3} 來對映。

命名引數

MyBatis封裝引數時由使用者來指定Map的key.

介面定義如下

public User getUserByIdAndUserName(@Param("id")Integer id, @Param("username")String username);

介面對應的 Mapper.xml 定義如下所示

<select id="getUserByIdAndUserName"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where id = #{id}
    and username = #{username}
</select>

POJO

多個引數一個個寫太麻煩了,這時候我們可以將引數列表進行封裝,將封裝物件作為 parameterType 的值。

介面定義如下

public User getUserByIdAndUserName(User user);

介面對應的 Mapper.xml 定義如下所示

命名引數:封裝引數時指定Map的key,

<select id="getUserByIdAndUserName"
        parameterType="com.example.mybatis.entity.User"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where id = #{id}
    and username = #{username}
</select>

與多個引數的不同之處在於,這裡是透過 #{屬性名} 來對映引數物件的具體屬性值的。

有時候為了方便,也可以直接使用Map來傳遞資料,但是使用Map會使得程式碼的可讀性很差,一般不推薦使用這種方式。

特殊情況

如果引數型別是Collection(List,Set)型別或者是陣列,MyBatis也會特殊處理

如果為Collection型別的,key為collection;如果為List型別的,key為list

public int addUserList(List<User> userList);

介面對應的 Mapper.xml 定義如下所示

<insert id="addUserList"
        parameterType="com.example.mybatis.entity.User"
        useGeneratedKeys="true"
        keyProperty="id">
    insert into user
    (username, user_email, user_city, age)
    values
    <foreach item="item"  collection="collection" separator=",">
        (#{item.username}, #{item.userEmail}, #{item.userCity}, #{item.age})
    </foreach>
</insert>

如果是陣列型別,key為array

介面定義如下

public int addUserList(User[] userList);

介面對應的 Mapper.xml 定義如下所示

<insert id="addUserList"
        parameterType="com.example.mybatis.entity.User"
        useGeneratedKeys="true"
        keyProperty="id">
    insert into user
    (username, user_email, user_city, age)
    values
    <foreach item="item"  collection="array" separator=",">
        (#{item.username}, #{item.userEmail}, #{item.userCity}, #{item.age})
    </foreach>
</insert>

#{}與${}取值區別

#{}是以預編譯的形式將引數設定到sql語句中,防止SQL隱碼攻擊,${}取出的值直接拼裝在SQL語句中,會有安全問題。

不過有時你就是想直接在 SQL 語句中插入一個不轉義的字串。 比如,像 ORDER BY,你可以這樣來使用

ORDER BY ${columnName}

這裡 MyBatis 不會修改或跳脫字元串。

當 SQL 語句中的後設資料(如表名或列名)是動態生成的時候,字串替換將會非常有用。 舉個例子,如果你想透過任何一列從表中 select 資料時,不需要像下面這樣寫:

@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);

@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);

@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);

可以只寫這樣一個方法:

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

其中 ${column} 會被直接替換,而 #{value} 會被使用 ? 預處理。因此你就可以像下面這樣來達到上述功能:

User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

這個方法也同樣適用於用來替換表名的情況。

#{}指定 jdbcType

只需要在可能執行插入、更新和刪除的且允許空值的列上指定 JDBC 型別。這是 JDBC 的要求而非 MyBatis 的要求。

為了以後可能的使用場景,MyBatis 透過內建的 jdbcType 列舉型別支援下面的 JDBC 型別。

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOB NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

在我們資料為null的時候,有些資料庫可能不能識別MyBatis對null的預設處理。比如Oracle,MyBatis對所有的null都對映成原生JDBC的OTHER型別,Oracle不能正確處理,但是MySQL卻能處理。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章