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去設置屬性。
開啟轉換:
然后查詢:
/** * 根據ID查詢,開了自動駝峰轉換 * * @param id * @return */ @Select("SELECT * FROM t_user WHERE id=#{id}") User loadByIdAutoAlias(Long id);
查看打印的結果,birth_day屬性填充到了對象中:
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: CC11001100@qq.com */ @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: CC11001100@qq.com */ @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,有點雞肋。