官网:http://www.mybatis.org/mybatis-3/index.html

在使用mybatis作为ORM框架时,我通常更喜欢使用注解而非xml配置文件的方式。
业务场景:添加记录之后需要返回自己自增长的主键字段值。
通常,我们会将DAO层写成如下代码(以添加员工Staff为例):

public interface StaffDAO {
    @InsertProvider(type=StaffProvider.class, method="buildSinleStaff")
    @Options(useGeneratedKeys=true, keyProperty="staff_id", keyColumn="staff_id")
    public int addStaff(Staff staff);
}

显然,希望在执行addStaff()后返回新添加的员工记录的主键字段值,在这里为staff_id(staff_id为主键字段,且为自增类型)。
但是!!!经过多次验证,依然发现,返回值始终为:1!
跟踪mybatis源码发现,返回值其实是添加的记录数,而不是新加记录的主键字段值,所以永远为1。

mybatis添加记录时序图:

查看org.apache.ibatis.executor.statement.PreparedStatementHandler源码实现:

@Override
public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
}

显然,返回值是受影响的记录数量,即:添加的记录数。

那么如何才能取得新添加记录的主键字段值呢?继续跟踪源码(org.apache.ibatis.executor.statement.PreparedStatementHandler):

@Override
public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
}

显然,在执行插入记录操作之后,还执行了如下操作:

Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);

在org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator中实现对主键字段的处理:

private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
    for (int i = 0; i < keyProperties.length; i++) {
        TypeHandler<?> th = typeHandlers[i];
        if (th != null) {
            Object value = th.getResult(rs, i + 1);
            metaParam.setValue(keyProperties[i], value);
        }
    }
}

恍然大悟!
在使用mybatis注解@Options(useGeneratedKeys=true)获取新添加记录的自增长主键字段值时,需要在执行添加操作之后,直接访问对象的主键字段属性即可取得对应值
回归到业务代码:

staffService.addStaff(staff);
long staffId = staff.getStaff_id(); // 执行添加操作之后获取对象主键字段值

最后需要说明:在mybatis中使用注解实现添加记录时,可以使用@Insert或者@InsertProvider 2个注解,都可以使用@Options注解获取新添加记录的自增长主键字段值。

【参考】
http://isilic.iteye.com/blog/1810782 Mybatis使用:Sql Annotation

使用mybatis注解@Options实现添加记录时返回主键值的更多相关文章

  1. mybatis添加记录时返回主键id

    参考:mybatis添加记录时返回主键id 场景 有些时候我们在添加记录成功后希望能直接获取到该记录的主键id值,而不需要再执行一次查询操作.在使用mybatis作为ORM组件时,可以很方便地达到这个 ...

  2. MyBatis插入记录时返回主键id的方法

    有时候插入记录之后需要使用到插入记录的主键,通常是再查询一次来获取主键,但是MyBatis插入记录时可以设置成返回主键id,简化操作,方法大致有两种. 对应实体类: public class User ...

  3. mybatis添加数据时返回主键 insert 返回主键值

    insert 返回主键值 useGeneratedKeys=“true” parameterType=“USer” keyProperty=“id”, <insert id="inse ...

  4. mybatis 08: 返回主键值的insert操作 + 利用UUID获取字符串(了解)

    返回主键值的insert操作 应用背景 图示说明 在上述业务背景下,涉及两张数据表的关联操作:用户表 + 用户积分表 传统操作:在对用户表执行完插入语句后,再次查询该用户的uid,将该uid作为外键, ...

  5. MyBatis在Oracle中插入数据并返回主键的问题解决

    引言:  在MyBatis中,希望在Oracle中插入数据之时,同一时候返回主键值,而非插入的条数... 环境:MyBatis 3.2 , Oracle. Spring 3.2   SQL Snipp ...

  6. [oracle] 如何使用myBatis在数据库中插入数据并返回主键

    在MyBatis中,希望在Oracle中插入数据的同时返回主键值,而非插入的条数. ① oracle使用 selectKey. U_USER_INFO_SEQ 是在数据库中定义好的这张表关联的序列se ...

  7. MyBatis在insert插入操作时返回主键ID的配置

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过Mapper.XML配置的方式来完成这个功能. 在 INSER ...

  8. mybatis 插入数据时返回主键

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:显然,假如主键是你生成后插入的,自然你已经有主键了,显然不需要我们再去获得,所以我们这里处理的是当主键 ...

  9. Mybatis在insert操作时返回主键

    今天在写项目的时候,遇到一个需求,就是在像数据库插入数据的时候,要保留插入数据的主键,以便后续进行级联时,可以将该主键作为另张表的外键. 但是在正常情况下我们使用插入语句返回的是int型,含义是影响该 ...

随机推荐

  1. thinkphp后台向前台传值没有传过去的小问题

    if($listyyarr){ $this->assign('listyyarr',$listyyarr); //$this->assign('nowDated',$endDated); ...

  2. jiVMware的网络配置Linux

    需求需要配置VMware的虚拟Linux的ip以达到本地可以访问,而且虚拟机Linux可以上网: 第一方案:选择桥接模式 思路:因为桥接可以,使得虚拟机Linux把本地当做一座桥一样连接到路由器,然后 ...

  3. 20170222==(MODBUS读取多个寄存器)

    MODBUS读取多个寄存器(功能码04) 为了简单我这里只用4个寄存器,当让你也可以用125个寄存器,但是最多也只能用125个寄存器的.每个寄存器有上面的表知道为一个字的大小即2个字节或者叫16比特位 ...

  4. 深度学习之 cnn 进行 CIFAR10 分类

    深度学习之 cnn 进行 CIFAR10 分类 import torchvision as tv import torchvision.transforms as transforms from to ...

  5. Linux CentOS7.0 (04)systemctl vs chkconfig、service

    CentOS 7.0中已经没有service命令,而是启用了systemctl服务器命令 systemctl 是系统服务管理器命令,它实际上将 service 和 chkconfig 这两个命令组合到 ...

  6. C#日志文件

    写日志文件是一个很常用的功能,以前都是别人写好的,直接调用的,近期写了一个小工具,因为比较小,所以懒得引用dll文件了,直接上网找了一个,很方便,现在记录下 public class LogClass ...

  7. Android:CheckBox控件

    1)ChexkBox继承自CompoundButton组件: 2)isChecked()--确定是否选中:setChecked(bool checked)--设置选中或取消选中: 3)监听事件:Com ...

  8. Hive:insert into table 与 insert overwrite table 区别

    创建测试表,来测试看看测试结果: create table test(name string,pwd string,createdate string)row format delimited fie ...

  9. find()用法

    >>> str = '编程改变世界'>>> str.find('编')0>>> str.find('程')1>>> str.fi ...

  10. Bank方案SQL

    用于演示的Bank方案对应的SQL: /* 1.branch 开展银行交易业务的场所 */ DROP TABLE IF EXISTS branch; CREATE TABLE branch -- 开展 ...