手敲MyBatis(十三章)-返回Insert操作自增索引值

1.目的

这一章的目的主要是插入语句以后返回插入记录的id,因为插入语句可分为要返回记录id,不要返回记录id的以及不同数据源类型执行的时机也不同(如:oracle不支持主键,需要先插入序列再增加,Mysql支持主键增加一条记录就会有索引)。

如下图,insert里包含selectKey,由selectKey去执行查询此次新增的id记录,我们看到selectKey标签上的属性有keyProperty、order、resultType。

  • keyProperty这个是把返回索引的索引放入id里
  • order为after则是在insert后执行selectKey
  • resultType则是查询返回的类型,示例里为Long

我们最主要的目的就是解析这样的selectKey,然后存入MappedStatement里到时执行时使用,执行Update时则执行selectKey的方法,最后在activity实体id赋值执行完的记录id。

 2.设计说明

标黄色的是修改的,其余都是新增的方法。

 1.构建时(builder)

在构建(builder)时,我们需要解析下selectKey的标签,而selectKey是在语句里,所以需要更改XMLStatementBuilder类添加解析selectKey的标签。最后把解析好的标签放入到addMappedStatement(),这里的动作是两次addMappedStatement(),为什么是两次呢?ps:可以看下面两个图。

  • 第一次,SqlCommandType是“SELECT”,代表selectKey本身的语句,需要存储一次MappedStatement
  • 第二次,SqlCommandType是“INSERT”,代表是selectKey父级的INSERT标签,它下面要包含这个selectKey的MappedStatement信息,然后如果有selectKey则创建SelectKeyGenerator对象,需要再一次存储MappedStatement。

ps此处看不懂可以调试全局看下,多看几遍就懂了为什么这样设计了。

2.selectKey执行时(executor keygen)

2.1 定义接口:

针对上述情况,需要定义接口KeyGenerator,定义方法为processBefore()(针对Oracle不支持主键的)和processAfter()(支持主键的,如MySql)

2.2 实现接口:

NoKenGenerator和SelectKeyGenerator,不要求返回记录的就执行NoKenGenerator(实现方法什么都不操作)。SelectKeyGenerator的实现则是执行查询索引操作,并将结果添加到insert的操作的实体里,这样就得到了索引。

3.执行时(executor)

我们存储到MappedStatement以后就要流转到执行时,因为SelectKey是查询,所以在Executor时

添加了重载的query()方法。

BaseExecutor实现新的query()方法,拿到了sql语句后,调用原有的doQuery,由SimpleExecutor类实现,此时就会调用BaseStatementHandler构造方法,这里新添加了generateKeys()方法,主要是检查下是否需要在insert前执行selectKey(如:Mysql是insert后,Oracle是insert前)。

执行了新增方法时,则需要添加调用KeyGenerator的processAfter()方法,这个方法依然要检查是否在insert后执行selectKey。

4.结果集的更改(resultset)

由于之前的结果集是只处理bean对象, 一般返回selectKey需要的基本类型,如ID是Long,所以这里需要添加createPrimitiveResultObject()方法获取类型处理器。

在createResultObject()此方法里则需要判断是否是基本类型,如果基本类型则调用createPrimitiveResultObject()。其余类型则还按之前代码走。

5.connection,连接的更改

由于要两个语句用一个连接如果两个连接则无法返回id索引,所以需要在获取连接处判断下是否有连接,如果有就不创建,没有就创建。

3.代码

3.1 selectKey执行操作

包:package cn.bugstack.mybatis.executor.keygen;

添加接口KeyGenerator,主要是用来执行SelectKey查询操作的,此接口定义了两个方法,

processBefore:是在不支持主键需要获取序列时调用,执行insert语句前调用

processAfter:是在支持主键在执行insert语句后嗲用

public interface KeyGenerator {

    /**
     * 针对Sequence主键而言,在执行insert sql前必须指定一个主键值给要插入的记录,
     * 如Oracle、DB2,KeyGenerator提供了processBefore()方法。
     */
    void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

    /**
     * 针对自增主键的表,在插入时不需要主键,而是在插入过程自动获取一个自增的主键,
     * 比如MySQL、PostgreSQL,KeyGenerator提供了processAfter()方法
     */
    void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
}

实现类SelectKeyGenera,有selectKey时实现执行selectKey的逻辑。

// step13新增
public class SelectKeyGenerator implements KeyGenerator {


    public static final String SELECT_KEY_SUFFIX = "!selectKey";
    private boolean executeBefore;
    private MappedStatement keyStatement;

    public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
        this.executeBefore = executeBefore;
        this.keyStatement = keyStatement;
    }

    @Override
    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        if (executeBefore) {
            processGe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值