1. 程式人生 > >Mybatis中,當插入資料後,返回最新主鍵id的幾種方法,及具體用法

Mybatis中,當插入資料後,返回最新主鍵id的幾種方法,及具體用法

               

一、前言                                   

  資料庫操作怎能少了INSERT操作呢?下面記錄MyBatis關於INSERT操作的筆記,以便日後查閱。

二、 insert元素 屬性詳解                            

  其屬性如下:

   parameterType ,入參的全限定類名或類型別名

   keyColumn ,設定資料表自動生成的主鍵名。對特定資料庫(如PostgreSQL),若自動生成的主鍵不是第一個欄位則必須設定

   keyProperty ,預設值unset,用於設定getGeneratedKeys方法或selectKey子元素返回值將賦值到領域模型的哪個屬性中

   useGeneratedKeys ,取值範圍true|false(預設值),設定是否使用JDBC的getGenereatedKeys方法獲取主鍵並賦值到keyProperty設定的領域模型屬性中。MySQL和SQLServer執行auto-generated key field,因此當資料庫設定好自增長主鍵後,可通過JDBC的getGeneratedKeys方法獲取。但像Oralce等不支援auto-generated key field的資料庫就不能用這種方法獲取主鍵了

   statementType ,取值範圍STATEMENT,PREPARED(預設值),CALLABLE

   flushCache

 ,取值範圍true(預設值)|false,設定執行該操作後是否會清空二級快取和本地快取

   timeout ,預設為unset(依賴jdbc驅動器的設定),設定執行該操作的最大時限,超時將拋異常

   databaseId ,取值範圍oracle|mysql等,表示資料庫廠家,元素內部可通過`<if test="_databaseId = 'oracle'">`來為特定資料庫指定不同的sql語句

三、一般的INSERT操作——返回值為插入的記錄數目                

mapper介面程式碼:

/** * 新增學生資訊 * @param student 學生例項 * @return 成功操作的記錄數目 
*/int add(EStudent student);

mapper.xml:

<insert id="add" parameterType="EStudent">  insert into TStudent(name, age) values(#{name}, #{age})</insert

四、執行INSERT操作後獲取記錄主鍵                        

mapper介面程式碼:

/** * 新增學生資訊 * @param student 學生例項 * @return 成功操作的記錄數目 */int add(EStudent student);

至於mapper.xml則分為兩種情況了,一種是資料庫(如MySQL,SQLServer)支援auto-generated key field,另一種是資料庫(如Oracle)不支援auto-generated key field的。

 1. 資料庫(如MySQL,SQLServer)支援auto-generated key field的情況

    手段①(推薦做法):

<insert id="add" parameterType="EStudent" useGeneratedKeys="true" keyProperty="id">  insert into TStudent(name, age) values(#{name}, #{age})</insert>

    手段②:

複製程式碼
<insert id="add" parameterType="EStudent"// 下面是SQLServer獲取最近一次插入記錄的主鍵值的方式  <selectKey resultType="_long" keyProperty="id" order="AFTER">    select @@IDENTITY as id  </selectKey>  insert into TStudent(name, age) values(#{name}, #{age})</insert>
複製程式碼

  由於手段②獲取主鍵的方式依賴資料庫本身,因此推薦使用手段①。

 2. 資料庫(如Oracle)不支援auto-generated key field的情況

複製程式碼
<insert id="add" parameterType="EStudent">  <selectKey keyProperty="id" resultType="_long" order="BEFORE">    select CAST(RANDOM * 100000 as INTEGER) a FROM SYSTEM.SYSDUMMY1  </selectKey>  insert into TStudent(id, name, age) values(#{id}, #{name}, #{age})</insert
複製程式碼

  注意:mapper介面返回值依然是成功插入的記錄數,但不同的是主鍵值已經賦值到領域模型實體的id中了。

五、 selectKey子元素 詳解                            

  作用:在insert元素和update元素中插入查詢語句。

  其屬性如下:

     keyProperty ,預設值unset,用於設定getGeneratedKeys方法或selectKey子元素返回值將賦值到領域模型的哪個屬性中

     resultType ,keyPropety所指向的屬性類全限定類名或類型別名

     order屬性 ,取值範圍BEFORE|AFTER,指定是在insert語句前還是後執行selectKey操作

     statementType ,取值範圍STATEMENT,PREPARED(預設值),CALLABLE

注意:selectKey操作會將操作查詢結果賦值到insert元素的parameterType的入參例項下對應的屬性中。並提供給insert語句使用

六、批量插入                                 

  方式1:

<insert id="add" parameterType="EStudent">  <foreach collection="list" item="item" index="index" separator=";">    INSERT INTO TStudent(name,age) VALUES(#{item.name}, #{item.age})  </foreach></insert>

上述方式相當語句逐條INSERT語句執行,將出現如下問題:
1. mapper介面的add方法返回值將是最一條INSERT語句的操作成功的記錄數目(就是0或1),而不是所有INSERT語句的操作成功的總記錄數目
2. 當其中一條不成功時,不會進行整體回滾。

  方式2(僅限於MSSQL):

複製程式碼
<insert id="add" parameterType="EStudent">  WITH R AS  <foreach collection="list" item="item" index="index" open="(" close=")" separator="union all">    SELECT #{item.name} as a, #{item.age} as</foreach>  INSERT INTO TStudent(name,age) SELECT a, b FROM R</insert>
複製程式碼

上述方式解決了方式1中的問題。但該方式僅限於MSSQL

  方式3(通用解決方法)方式3(MSSQL):

 INSERT INTO TStudent(name,age)   <foreach collection="list" item="item" index="index" open="(" close=")" separator="union all">    SELECT #{item.name} as a, #{item.age} as</foreach>

該方式與方式2效果一樣,若為Oracle則採用

INSERT INTO TStudent(name,age)   <foreach collection="list" item="item" index="index" open="(" close=")" separator="union all">    SELECT #{item.name} as a, #{item.age} as b FROM DUAL  </foreach>

INSERT INTO TStudent(name,age)   <foreach collection="list" item="item" index="index" open="(" close=")" separator="union all">    SELECT #{item.name} as a, #{item.age} as b FROM DUAL  </foreach>