映射插入语句 insert

<insert id="insert" parameterType="com.study.mybatis.entity.Country">
  <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
    SELECT LAST_INSERT_ID()
  </selectKey>
  insert into country (`NAME`, CODE)
  values (#{name,jdbcType=VARCHAR}, #{code,jdbcType=VARCHAR})
</insert>

标签包含如下属性。

  1. id:命名空间中的唯一标识符,可用来代表这条语句。

  2. parameterType:即将传入的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以推断出传入语句的具体参数,因此不建议配置该属性

  3. flushCache:默认值为 true,任何时候只要该语句被调用,都会清空一级缓存和二级缓存。

  4. timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。

  5. statementType:对于 STATEMENT、PREPARED、CALLABLE,MyBatis 会分别使用对应的 Statement、PreparedStatement、CallableStatement,默认值为 PREPARED。

  6. useGeneratedKeys:默认值为 false。如果设置为 true,MyBatis 会使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键。

  7. keyProperty:MyBatis 通过 getGeneratedKeys 获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表。

  8. keyColumn:仅对 INSERT 和 UPDATE 有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如 PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

  9. databaseId:如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 的或匹配当前 databaseId 的语句。如果同时存在带 databaseId 和不带 databaseId 的语句,后者会被忽略。

接下来看一下接口中对应的方法int insert(Country row);该方法的 int 类型返回值并不是数据库返回的主键的值,而是 SQL 语句执行完后影响的行数,这个值和日志中的Updates:1是一致的。如果是批量插入、批量更新、批量删除,这里的数字会是插入的数据行数、更新的数据行数、删除的数据行数。

返回自增后的主键值

  • useGeneratedKeys 设置为 true 时,MyBatis 会使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键。获得主键值后将其赋值给 keyProperty 配置的属性。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置 keyColumn 属性,按顺序指定数据库的列,这里列的值会和 keyProperty 配置的属性一一对应。

  • useGeneratedKeys 这种回写主键的方法只适用于支持主键自增的数据库。有些数据库(如 Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给 id,再将数据插入数据库。对于这种情况,可以采用另外一种方式:使用标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

    selectKey 标签的 keyColumnkeyProperty 和上面 useGeneratedKeys 的用法含义相同,这里的 resultType 用于设置返回值类型。

    order 属性的设置和使用的数据库有关:

    • 在 MySQL 数据库中,order 属性设置的值是 AFTER,因为当前记录的主键值在 insert 语句执行成功后才能获取到

    • 在 Oracle 数据库中,order 的值要设置为 BEFORE,这是因为 Oracle 中需要先从序列获取值,然后将值作为主键插入到数据库中。以下是 Oracle 数据库的用法示例:

      <insert id="insert" parameterType="com.study.mybatis.entity.Country">
        <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
          SELECT SEQ_ID.nextval FROM dual
        </selectKey>
        insert into country (ID, `NAME`, CODE)
        values (
        	#{id,jdbcType=INTEGER},
        	#{name,jdbcType=VARCHAR}, 
        	#{code,jdbcType=VARCHAR}
        )
      </insert>
      

      注意:

      Oracle 方式的 INSERT 语句中明确写出了 id 列和值#{id},因为执行 selectKey 中的语句后 id 就有值了,我们需要把这个序列值作为主键值插入到数据库中,所以必须指定 id 列,如果不指定这一列,数据库就会因为主键不能为空而抛出异常。

批量新增回写主键值

从 MyBatis 3.3.1 版本开始,MyBatis 开始支持批量新增回写主键值的功能,这个功能要求数据库主键值为自增类型,同时还要求该数据库提供的 JDBC 驱动可以支持返回批量插入的主键值(JDBC 提供了接口,但并不是所有数据库都完美实现了该接口),因此到目前为止,可以完美支持该功能的仅有 MySQL 数据库

如果要在 MySQL 中实现批量插入返回自增主键值,只需要在原来代码基础上进行如下修改即可:

<insert id="insertList" useGeneratedKeys="true" keyProperty="id">
  ...批量新增的SQL语句...
</insert>

和单表一样,此处增加了 useGeneratedKeys keyProperty 两个属性

Last updated