Mybatis新增同时返回主键功能的两种方式

Mybatis新增并返回主键功能


本人使用的是Mybatis3.X的版本

官方文档给出了两种方式实现:

  1. useGeneratedKeys:(仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
    如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就OK了。
  2. 如果你的数据库不支持自动生成主键的字段。你可以使用子标签来实现。

示例

省略了实体类和mapper接口层的代码,只给出xml文件的代码作为示例

<mapper namespace="com.mirt.mybatis_demo.mapper.AutoIncrementMapper">

    <resultMap id="BaseResult" type="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
        <result column="id" property="id"/>
        <result column="comment" property="comment"/>
        <result column="create_time" property="createTime"/>
    resultMap>

    <insert id="saveOneByUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
        insert into auto_increment_table (comment, create_time) values (#{comment},now());
    insert>

    <insert id="saveOneBySelectKey" parameterType="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
        <selectKey resultType="int" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID();
        selectKey>
        insert into auto_increment_table (comment, create_time) values (#{comment},now());
    insert>
mapper>

此处定义了两种方法 saveOneByUseGeneratedKeys,saveOneBySelectKey
用于演示官方给出的两种方法是否可行。

给出测试类下的方法以及结果

	@Test
    public void saveOneByUseGeneratedKeys() {
        AutoIncrementEntity aie = new AutoIncrementEntity();
        aie.setComment("useGeneratedKeys");
        boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
        if (res) {
            System.out.println(aie);
        }else {
            System.out.println("insert fail");
        }
    }

    @Test
    public void saveOneBySelectKey() {
        AutoIncrementEntity aie = new AutoIncrementEntity();
        aie.setComment("selectKey");
        boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
        if (res) {
            System.out.println(aie);
        }else {
            System.out.println("insert fail");
        }
    }

返回结果为

{id:1}
{id:2}

可以看出来确实返回了自增的主键。


源码

package org.apache.ibatis.executor.keygen;

import java.sql.Statement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;

public interface KeyGenerator {
    void processBefore(Executor var1, MappedStatement var2, Statement var3, Object var4);

    void processAfter(Executor var1, MappedStatement var2, Statement var3, Object var4);
}

mybatis的KeyGenerator接口提供了两个方法,一个是执行前一个是执行后,在上面的示例中由于主键是在插入后才获得的,所以使用的都是processAfter这个方法。

该接口有三个实现类,默认使用的是Jdbc3KeyGenerator这个实现类。

	public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        this.processBatch(ms, stmt, this.getParameters(parameter));
    }

    public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) {
        ResultSet rs = null;

        try {
            rs = stmt.getGeneratedKeys();
            Configuration configuration = ms.getConfiguration();
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            String[] keyProperties = ms.getKeyProperties(); // 可以配置多个keyproperties
            ResultSetMetaData rsmd = rs.getMetaData();
            TypeHandler<?>[] typeHandlers = null;
            MetaObject metaParam;
            if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {
                for(Iterator var10 = parameters.iterator(); var10.hasNext(); this.populateKeys(rs, metaParam, keyProperties, typeHandlers)) {
                    Object parameter = var10.next();
                    if (!rs.next()) {
                        break;
                    }

                    metaParam = configuration.newMetaObject(parameter);
                    if (typeHandlers == null) {
                        typeHandlers = this.getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);
                    }
                }
            }
        } catch (Exception var20) {
            throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + var20, var20);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception var19) {
                    ;
                }
            }

        }

    }
    
    // 将获得的值存入到实体类指定的字段
  	private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
        for(int i = 0; i < keyProperties.length; ++i) {
            String property = keyProperties[i];
            TypeHandler<?> th = typeHandlers[i];
            if (th != null) {
                Object value = th.getResult(rs, i + 1);
                metaParam.setValue(property, value);
            }
        }

    }

mybatis的官方文档中对于keyPropwety有如下描述

(仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

从源码中了解到keyProperty也确实可以支持设置多个,统一在插入操作前后统一存入。

有一点需要注意就是如果你的主键没有setter方法的话,这里是会报错的。mybatis没有办法把生成的主键信息存回到实体类当中去。

你可能感兴趣的:(各种小问题)