本篇文章針對前面沒有講到的XML映射配置文件做一個補充說明。
1. selectKey自動生成主鍵
對於不支持自動生成主鍵列的數據庫和可能不支持自動生成主鍵的 JDBC 驅動,MyBatis 有另外一種方法來生成主鍵。
這裏有一個簡單(也很傻)的示例,它可以生成一個隨機 ID(不建議實際使用,這裏只是爲了展示 MyBatis 處理問題的靈活性和寬容度):
<insert id="insert">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
SELECT FLOOR(RAND()*10000) AS id
</selectKey>
INSERT INTO `user`(`id`,`name`, `phone`, `birthday`) VALUES (#{id}, #{u.name}, #{u.phone}, #{u.birthday})
</insert>
單元測試:
@Test
void insert() throws ParseException {
User user = new User();
user.setName("啊隨");
user.setPhone("11111111111");
user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1996-07-18"));
userMapper.insert(user);
}
運行結果:
並不建議這樣做,畢竟絕大多數數據庫都有自增主鍵的功能,不需要更沒必要自動生成一個隨機數來當作id。這裏只是演示一下selectKey標籤還有這種用法。
屬性 | 描述 |
---|---|
keyProperty | selectKey 語句結果應該被設置到的目標屬性。如果生成列不止一個,可以用逗號分隔多個屬性名稱。 |
keyColumn | 返回結果集中生成列屬性的列名。如果生成列不止一個,可以用逗號分隔多個屬性名稱。 |
resultType | 結果的類型。通常 MyBatis 可以推斷出來,但是爲了更加準確,寫上也不會有什麼問題。MyBatis 允許將任何簡單類型用作主鍵的類型,包括字符串。如果生成列不止一個,則可以使用包含期望屬性的 Object 或 Map。 |
order | 可以設置爲 BEFORE 或 AFTER。如果設置爲 BEFORE,那麼它首先會生成主鍵,設置 keyProperty 再執行插入語句。如果設置爲 AFTER,那麼先執行插入語句,然後是 selectKey 中的語句 - 這和 Oracle 數據庫的行爲相似,在插入語句內部可能有嵌入索引調用。 |
statementType | 和前面一樣,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 類型的映射語句,分別代表 Statement, PreparedStatement 和 CallableStatement 類型。 |
2. 返回主鍵id
在實際應用中,常常需要返回insert語句的主鍵id。配置起來很簡單,只需:
- 指定insert標籤的useGeneratedKeys屬性爲true
- 指定insert標籤的keyProperty屬性所對應的實體類的屬性名
- 指定insert標籤的keyColumn屬性所對應的數據表的字段名
<insert id="insertAndGetId" parameterType="com.yky.springboot.entities.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO `user`(`name`, `phone`, `birthday`) VALUES (#{u.name}, #{u.phone}, #{u.birthday})
</insert>
返回的主鍵id會直接注入到user對象中。
@Test
void insertAndGetId() throws ParseException {
User user = new User();
user.setName("id返回");
user.setPhone("11111111111");
user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1996-07-18"));
userMapper.insertAndGetId(user);
System.out.println(user.getId());
}
3. sql標籤代碼重用
可以使用sql標籤將多個地方會用到的代碼抽取出來。
<sql id="allColumn">
`id`, `name`, `phone`, `birthday`
</sql>
直接使用include標籤進行引用
<select id="selectById" resultType="User" >
SELECT
<include refid="allColumn"></include>
FROM `user` WHERE id = #{id}
</select>
4. 佔位符與字符串替換
前面我們用了很多次#{}佔位符,默認情況下,使用 #{} 參數語法時,MyBatis 會創建 PreparedStatement 參數佔位符,並通過佔位符安全地設置參數(就像使用 ? 一樣)。 這樣做更安全,更迅速,通常也是首選做法,不過有時你就是想直接在 SQL 語句中直接插入一個不轉義的字符串。這時就需要用到${}了。
比如:
ORDER BY ${columnName}
那什麼時候用 ${} 呢?當SQL語句中的表名/列名需要動態生成時,則需要用到 ${}。因爲表名/列名需要直接替換進SQL語句,而不能經過轉義。
在這裏舉一個使用字符串替換的例子:
映射接口:
/**
* 根據列名和改列所對應的值匹配
* @param columnName 列名
* @param value 值
* @return
*/
List<User> selectByColumn(@Param("columnName") String columnName,@Param("value") String value);
xml映射配置:
<select id="selectByColumn" resultType="User">
SELECT
<include refid="allColumn"></include>
FROM `user`
WHERE ${columnName} = #{value}
</select>
單元測試代碼:
@Test
void selectByColumn() {
List<User> users = userMapper.selectByColumn("name", "小明");
System.out.println(users);
}
Mybatis不推薦我們這樣做,因爲這種用法會導致潛在的SQL注入攻擊。如果非要這樣用,推薦對輸入的參數進行校驗,以防止非法SQL語句被執行。