Skip to content

Files

Latest commit

584123d · Jan 10, 2020

History

History
This branch is 51 commits behind baomidou/mybatis-plus-samples:master.

mybatis-plus-sample-sequence

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Aug 24, 2019
Jan 10, 2020
Nov 28, 2019

主键Sequence

针对有序列的数据库:比如Oracle,SQLServer等

让我们以Oracle举例: 我们可以通过以下几个简单步骤,就可以完成Mybatis-Plus主键Sequence的定义

1.定义IKeyGenerator的实现

Mybatis-Plus已经定义好了常见的数据库主键序列类: 比如:OracleKeyGenerator

如果你使用了mybatis-plus-boot-starter, 那么我们只需要在@Configuration类中定义好@Bean

    @Bean
    public OracleKeyGenerator oracleKeyGenerator(){
        return new OracleKeyGenerator();
    }

如果没有使用mybatis-plus-boot-starter, 那么需要手动注入:

GlobalConfiguration配置KeyGenerator

  GlobalConfiguration gc = new GlobalConfiguration();
  gc.setKeyGenerator(new OracleKeyGenerator());

2.配置KeySequence注解

实体类配置主键Sequence,指定主键@TableId(type=IdType.INPUT)//不能使用AUTO

@TableName("TEST_SEQUSER")
@KeySequence("SEQ_TEST")//类注解
public class TestSequser{
  @TableId(value = "ID", type = IdType.INPUT)
  private Long id;

}
  • 支持父类定义@KeySequence, 子类使用,这样就可以几个表共用一个Sequence

如果主键是String类型的,也可以使用

如何使用Sequence作为主键,但是实体主键类型是String 也就是说,表的主键是varchar2, 但是需要从sequence中取值

  • 1.实体定义@KeySequence 注解clazz指定类型String.class
  • 2.实体定义主键的类型String
  • 3.注意:oracle的sequence返回的是Long类型,如果主键类型是Integer,可能会引起ClassCastException
@KeySequence(value = "SEQ_ORACLE_STRING_KEY", clazz = String.class)
public class YourEntity{
    
    @TableId(value = "ID_STR", type = IdType.INPUT)
    private String idStr;
    ...
}

底层实现

mybatis原生提供了接口

先看下com.baomidou.mybatisplus.core.metadata.TableInfoHelper这个类:

    /**
     * 自定义 KEY 生成器
     */
    public static KeyGenerator genKeyGenerator(TableInfo tableInfo, MapperBuilderAssistant builderAssistant,
                                               String baseStatementId, LanguageDriver languageDriver) {
        IKeyGenerator keyGenerator = GlobalConfigUtils.getKeyGenerator(builderAssistant.getConfiguration());
        if (null == keyGenerator) {
            throw new IllegalArgumentException("not configure IKeyGenerator implementation class.");
        }
        String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        Class<?> resultTypeClass = tableInfo.getKeySequence().clazz();
        StatementType statementType = StatementType.PREPARED;
        String keyProperty = tableInfo.getKeyProperty();
        String keyColumn = tableInfo.getKeyColumn();
        SqlSource sqlSource = languageDriver.createSqlSource(builderAssistant.getConfiguration(),
            keyGenerator.executeSql(tableInfo.getKeySequence().value()), null);
        builderAssistant.addMappedStatement(id, sqlSource, statementType, SqlCommandType.SELECT, null, null, null,
            null, null, resultTypeClass, null, false, false, false,
            new NoKeyGenerator(), keyProperty, keyColumn, null, languageDriver, null);
        id = builderAssistant.applyCurrentNamespace(id, false);
        MappedStatement keyStatement = builderAssistant.getConfiguration().getMappedStatement(id, false);
        SelectKeyGenerator selectKeyGenerator = new SelectKeyGenerator(keyStatement, true);
        builderAssistant.getConfiguration().addKeyGenerator(id, selectKeyGenerator);
        return selectKeyGenerator;    
    }
  1. 通过反射获取到实体的KeySequence注解,继而能拿到定义的Sequence序列名
  2. 然后产生SelectKeyGenerator对象,这个对象是mybatis原生的主键生成器
  3. SelectKeyGenerator绑定到insert/insertBatch的statement上面
  4. 通过上述3步,就完成了自动注入主键生成的SQL

SelectKeyGenerator对象是mybatis原生的主键生成器, 会在:执行sql之前调用主键生成器的方法获取主键结果,插入到insert语句中; 在执行成功之后把主键的值回塞到实体对象中,这样我们只需通过对象的getId()方法就可以获取到主键值