MyBatis註解開發-@Insert和@InsertProvider的使用

@Insert和@InsertProvider的使用

首先,在mybatis-generator.xml中配置返回主鍵

UserMapper中的

  • @SelectKey:返回主鍵,具體解釋見下面說明
  • @InsertProvider:type指明SQL工廠類,method是工廠類裡對應的方法

@SelectKey註解源碼

  • statement是要運行的SQL語句,它的返回值通過resultType來指定before表示查詢語句statement運行的時機
  • keyProperty表示查詢結果賦值給代碼中的哪個對象,keyColumn表示將查詢結果賦值給數據庫表中哪一列
  • keyProperty和keyColumn都不是必需的,有沒有都可以
  • before=true,插入之前進行查詢,可以將查詢結果賦給keyProperty和-keyColumn,賦給keyColumn相當於更改數據庫
  • befaore=false,先插入,再查詢,這時隻能將結果賦給keyProperty
  • 賦值給keyProperty用來“讀”數據庫,賦值給keyColumn用來寫數據庫

selectKey的兩大作用:

  • 1、生成主鍵;
  • 2、獲取剛剛插入數據的主鍵。

註意:在MYSQL 中 , order是AFTER , 因為當前及記錄的主鍵值在insert語句執行成功之後才能拿到 , 而在ORACLE中 ,oder是BEFORE , 因為ORACLE需要先從序列取到值 , 再將其作為主鍵插入到數據庫

另外,附上UserMapper.xml形式的返回主鍵方法

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
實體類的映射文件
namespace 指定接口的類全名
-->
<mapper namespace="com.wzl.dao.UserMapper">
       <!--
            方案一: 這表的主鍵必須是自增長的 auto_increment
                 useGeneratedKeys="true" 讓自增長的主鍵開啟返回功能
                 keyColumn="id"  user表中主鍵列
                 keyProperty="id" user實體主鍵屬性
                 註意:支持主鍵自增類型的數據庫 MySQL 和 SqlServer , oracle不支持
       -->
    <insert id="addUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
         insert into user values(null,#{user.username},#{user.birthday},#{user.sex},#{user.address})
    </insert>
    <!--
            方案二: <selectKey>
             keyColumn="id" user表中主鍵列
             keyProperty="id" user實體主鍵屬性
             resultType="int" user實體主鍵屬性類型
             order="AFTER"  表示此標簽內部sql語句在insert執行之前(執行),還是之後執行(執行)
                AFTER 之後執行【在自增主鍵時】
                BEFORE 之前執行【使用指定主鍵時】
在MYSQL 中 , order是AFTER , 因為當前及記錄的主鍵值在insert語句執行成功之後才能拿到 , 而在ORACLE中 ,oder是BEFORE , 因為ORACLE需要先從序列取到值 , 再將其作為主鍵插入到數據庫
    -->
    <insert id="addUser2">
        <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user values(null, #{username},#{birthday},#{sex},#{address})
    </insert>
</mapper>

使用InsertProvider註解報錯解決過程

目前項目在使用mybatis,並且是使用註解的方式。

在使用InsertProvider註解的時候報瞭一下的錯誤:

org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation.  Cause: org.apache.ibatis.builder.BuilderException: Error creating SqlSource for SqlProvider. Method……..

註解是如下這個樣子的

@InsertProvider(method = "insertlist",type=SqlProvider.class)
 public int insertInnerTable(List list,String dbTable);

思路是要寫一個通用的插入一個集合的方法,但是在執行的時候就報瞭上面的錯誤。在網上查資料未果。

於是隻能自己動手,豐衣足食瞭。

一步步跟斷點,跟到mybatis瞭報錯的方法中,發現瞭如下的代碼

try {
      this.sqlSourceParser = new SqlSourceBuilder(config);
      this.providerType = (Class<?>) provider.getClass().getMethod("type").invoke(provider);
      providerMethodName = (String) provider.getClass().getMethod("method").invoke(provider);
      for (Method m : this.providerType.getMethods()) {
        if (providerMethodName.equals(m.getName())) {
          if (m.getParameterTypes().length < 2
              && m.getReturnType() == String.class) {
            this.providerMethod = m;
            this.providerTakesParameterObject = m.getParameterTypes().length == 1;
          }
        }
      }
    } catch (Exception e) {
      throw new BuilderException("Error creating SqlSource for SqlProvider.  Cause: " + e, e);
    }

註意標黃的位置,終於發現導致錯誤的罪魁禍首瞭,原來是這裡限制瞭參數的個數,不能操作兩個參數的啊。

於是將方法以及註解改為如下形式

@InsertProvider(method = "insert",type=SqlProvider.class)
 public int insert(SqlContext sqlContext);

在SqlProvider中對應的方法為

public String insert(SqlContext sqlContext){
      ........
}

至此問題解決!

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。 

推薦閱讀: