1. 程式人生 > >mybatis之@Mapper註解

mybatis之@Mapper註解

1. mybatis支援的對映方式

mybatis支援的對映方式有基於xml的mapper.xml檔案、基於java的使用Mapper介面class,簡單學習一下mybatis使用介面來配置對映的方法。

介面方法註解主要是四個:@Insert、@Delete、@Update、@Select

2. 如何使用介面註解來對映

下面的實驗都是基於t_user表的,其結構如下:

DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user (
    id BIGINT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(100) NOT NULL ,
    passwd CHAR(32) NOT NULL,
    birth_day DATETIME
) CHARSET UTF8;

2.1 增 @Insert

插入記錄的時候麻煩的一點是主鍵如何生成,對此基本上有三種方案,分別是手動指定(應用層)、自增主鍵(資料層單表)、選擇主鍵(資料層多表)。

1. 在應用層手動指定主鍵

手動指定的方式不把主鍵區別看待,插入之前在應用層生成物件的時候就會給主鍵一個值,插入的時候與普通欄位沒啥區別。

/**
 * 插入記錄,手動分配主鍵
 *
 * @param user
 * @return
 */
@Insert("INSERT INTO t_user (id, username, passwd) VALUES (#{id}, #{username}, #{passwd})")
int addUserAssignKey(User user);

在上面的這個例子中,mybatis並不知道到底哪個欄位是主鍵,id雖然是主鍵欄位,但並沒有被區別對待。

注意#{username}這種寫法,是把User作為了當前上下文,這樣訪問User的屬性的時候直接寫屬性名字就可以了。

2. 表自增主鍵

自增主鍵對應著XML配置中的主鍵回填,一個簡單的例子:

/**
 * 插入記錄,資料庫生成主鍵
 *
 * @param user
 * @return
 */
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO t_user (username, passwd) VALUES (#{username}, #{passwd})")
int addUserGeneratedKey(User user);

使用Option來對應著XML設定的select標籤的屬性,userGeneratordKeys表示要使用自增主鍵,keyProperty用來指定主鍵欄位的欄位名。

自增主鍵會使用資料庫底層的自增特性。

 

3. 選擇主鍵

選擇主鍵從資料層生成一個值,並用這個值作為主鍵的值。

/**
 * 插入記錄,選擇主鍵
 *
 * @param user
 * @return
 */
@Insert("INSERT INTO t_user (username, passwd) VALUES (#{username}, #{passwd})")
@SelectKey(statement = "SELECT UNIX_TIMESTAMP(NOW())", keyColumn = "id", keyProperty = "id", resultType = Long.class, before = true)
int addUserSelectKey(User user);

2.2 刪 @Delete

刪除的時候只要把語句條件神馬的寫在@Delete註解的value裡就好了,返回一個int型別是被成功刪除的記錄數。

/**
 * 刪除記錄
 *
 * @param id
 * @return
 */
@Delete("DELETE FROM t_user WHERE id=#{id}")
int delete(Long id);

2.3 改 @Update

修改的時候和刪除一樣只要把SQL語句寫在@Update的value中就好了,返回一個int型別表示被修改的記錄行數。

/**
 * 修改記錄
 *
 * @param user
 * @return
 */
@Update("UPDATE t_user SET username=#{username}, passwd=#{passwd} WHERE id=#{id}")
int update(User user);

2.4 查 @Select

查詢的時候稍稍有些複雜,因為查詢會涉及到如何將查出來的欄位設定到物件上,通常有那麼三種辦法:

1. 在SQL語句中手動指定別名來匹配

在寫SQL語句的時候,手動為每一個欄位指定一個別名來跟物件的屬性做匹配,適用於表字段名與物件屬性名差異很大沒有規律並且表字段不多的情況。

/**
 * 根據ID查詢,手動設定別名
 *
 * @param id
 * @return
 */
@Select("SELECT id, username, passwd, birth_day AS birthDay FROM t_user WHERE id=#{id}")
User loadByIdHandAlias(Long id);

2. 使用mybatis的自動下劃線駝峰轉換

mybatis有一個選項叫mapUnderscoreToCamelCase,當表中的欄位名與物件的屬性名相同只是下劃線和駝峰寫法的差異時適用。

配置了mapUnderscoreToCamelCase之後mybatis在將ResultSet查出的資料設定到物件的時候會嘗試先將下劃線轉換為駝峰然後前面拼接set去設定屬性。

開啟轉換:

image

然後查詢:

/**
 *  根據ID查詢,開了自動駝峰轉換
 *
 * @param id
 * @return
 */
@Select("SELECT * FROM t_user WHERE id=#{id}")
User loadByIdAutoAlias(Long id);

檢視列印的結果,birth_day屬性填充到了物件中:

 image

3. 使用ResultMap

對於表的欄位名和物件的屬性名沒有太大相同點並且表中的欄位挺多的情況下,應該使用ResultMap做適配。

/**
 * 使用ResultMap
 *
 * @param id
 * @return
 */
@Results(id = "userMap", value = {
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "username", property = "username"),
        @Result(column = "passwd", property = "passwd"),
        @Result(column = "birth_day", property = "birthDay")
})
@Select("SELECT * FROM t_user WHERE id=#{id}")
User loadByIdResultMap(Long id);

@Results對應著XML中的ResultMap,同時可以為其指定一個id,其它地方可以使用這個id來引用它,比如要引用上面的這個Results:

/**
 * 引用其他的Result
 *
 * @param id
 * @return
 */
@ResultMap("userMap")
@Select("SELECT * FROM t_user WHERE id=#{id}")
User loadByIdResultMapReference(Long id);

使用@ResultMap來引用一個已經存在的ResultMap,這個ResultMap可以是在Java中使用@Results註解定義的,也可以是在XML中使用resultMap標籤定義的。

 

2.5 樣例程式碼

User.java

package org.cc11001100.mybatis.domain;
 
import org.apache.ibatis.type.Alias;
 
import java.util.Date;
 
/**
 * @author: CC11001100
 * @date: 2017/11/9 18:33
 * @email: [email protected]
 */
@Alias("user")
public class User {
 
    private Long id;
 
    private String username;
 
    private String passwd;
 
    private Date birthDay;
 
    public User() {
    }
 
    public User(String username, String passwd) {
        this.username = username;
        this.passwd = passwd;
    }
 
    public User(Long id, String username, String passwd) {
        this.id = id;
        this.username = username;
        this.passwd = passwd;
    }
 
    public Date getBirthDay() {
        return birthDay;
    }
 
    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getPasswd() {
        return passwd;
    }
 
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", passwd='" + passwd + '\'' +
                ", birthDay=" + birthDay +
                '}';
    }
}

UserMapper.java

package org.cc11001100.mybatis.mapper;
 
import org.apache.ibatis.annotations.*;
import org.cc11001100.mybatis.domain.User;
import org.springframework.stereotype.Repository;
 
/**
 * @author: CC11001100
 * @date: 2017/11/9 18:16
 * @email: [email protected]
 */
@Mapper
@Repository
public interface UserMapper {
 
    /**
     * 插入記錄,手動分配主鍵
     *
     * @param user
     * @return
     */
    @Insert("INSERT INTO t_user (id, username, passwd) VALUES (#{id}, #{username}, #{passwd})")
    int addUserAssignKey(User user);
 
    /**
     * 插入記錄,資料庫生成主鍵
     *
     * @param user
     * @return
     */
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("INSERT INTO t_user (username, passwd) VALUES (#{username}, #{passwd})")
    int addUserGeneratedKey(User user);
 
    /**
     * 插入記錄,選擇主鍵
     *
     * @param user
     * @return
     */
    @Insert("INSERT INTO t_user (username, passwd) VALUES (#{username}, #{passwd})")
    @SelectKey(statement = "SELECT UNIX_TIMESTAMP(NOW())", keyColumn = "id", keyProperty = "id", resultType = Long.class, before = true)
    int addUserSelectKey(User user);
 
    /**
     * 刪除記錄
     *
     * @param id
     * @return
     */
    @Delete("DELETE FROM t_user WHERE id=#{id}")
    int delete(Long id);
 
    /**
     * 修改記錄
     *
     * @param user
     * @return
     */
    @Update("UPDATE t_user SET username=#{username}, passwd=#{passwd} WHERE id=#{id}")
    int update(User user);
 
    /**
     * 根據ID查詢,手動設定別名
     *
     * @param id
     * @return
     */
    @Select("SELECT id, username, passwd, birth_day AS birthDay FROM t_user WHERE id=#{id}")
    User loadByIdHandAlias(Long id);
 
    /**
     *  根據ID查詢,開了自動駝峰轉換
     *
     * @param id
     * @return
     */
    @Select("SELECT * FROM t_user WHERE id=#{id}")
    User loadByIdAutoAlias(Long id);
 
    /**
     * 使用ResultMap
     *
     * @param id
     * @return
     */
    @Results(id = "userMap", value = {
            @Result(id=true, column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "passwd", property = "passwd"),
            @Result(column = "birth_day", property = "birthDay")
    })
    @Select("SELECT * FROM t_user WHERE id=#{id}")
    User loadByIdResultMap(Long id);
 
    /**
     * 引用其他的Result
     *
     * @param id
     * @return
     */
    @ResultMap("userMap")
    @Select("SELECT * FROM t_user WHERE id=#{id}")
    User loadByIdResultMapReference(Long id);
 
}

3. 總結

使用介面註解的優點:

  1. 比較方便,快速編寫對映語句

使用介面註解的缺點:

  1. 適用於比較簡單的配置,當太複雜了介面就搞不定了。

      2. 不能使用動態SQL,有點雞肋。