通用mapper用oracle序列作為主鍵

zlystudy發表於2020-10-09

通用mapper用oracle序列作為主鍵

最近使用通用mapper開發專案,公司用的oracle資料庫,持久層用的是通用mapper,公司要求用資料庫的序列,按照官方的配置,可能是自己的原因,總是配置不對,自己看了一下原始碼,發現用key註解就可以實現,具體配置如下:

    @Id
    @Column(name = "id")
    @KeySql(sql = "select SEQ_ID.nextval from dual", order= ORDER.DEFAULT)
    private Integer id;

平常用mybatis的時候,mybatis 有個selectKey標籤,那麼通用mapper應該是啟動的時候把註解的內容封裝成selectKey了。於是找到了BaseInsertProvider這個類。

   public String insert(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
   }

這個insert方法就是儲存的方法,getEntityClass就是解析實體。點進去看一下。

public Class<?> getEntityClass(MappedStatement ms) {
       EntityHelper.initEntityNameMap(returnType, mapperHelper.getConfig());
    }

找到了initEntityNameMap 方法,再跟進去。

 public static synchronized void initEntityNameMap(Class<?> entityClass, Config config) {
        if (entityTableMap.get(entityClass) != null) {
            return;
        }
        //建立並快取EntityTable
        EntityTable entityTable = resolve.resolveEntity(entityClass, config);
        entityTableMap.put(entityClass, entityTable);
    }

終於找到了解析resolve.resolveEntity(entityClass, config),點進去看看。
應為註解是寫的在Id欄位上的,我們就重點看解析field的方法。

 for (EntityField field : fields) {
         
            if (config.isUseSimpleType()){
            //省略了一些方法
            processField(entityTable, field, config, style);
        }

然後看processField,找到處理主鍵的方法。

      //處理主鍵策略
        processKeyGenerator(entityTable, field, entityColumn);
 protected void processKeyGenerator(EntityTable entityTable, EntityField field, EntityColumn entityColumn) {
        //KeySql 優先順序最高
        if (field.isAnnotationPresent(KeySql.class)) {
            processKeySql(entityTable, entityColumn, field.getAnnotation(KeySql.class));
        } else if (field.isAnnotationPresent(GeneratedValue.class)) {
            //執行 sql - selectKey
            processGeneratedValue(entityTable, entityColumn, field.getAnnotation(GeneratedValue.class));
        }
    }

看到了keysql 這個註解,於是看下面是怎麼處理的。

    protected void processKeySql(EntityTable entityTable, EntityColumn entityColumn, KeySql keySql) {
        if (keySql.useGeneratedKeys()) {
            entityColumn.setIdentity(true);
            entityColumn.setGenerator("JDBC");
            entityTable.setKeyProperties(entityColumn.getProperty());
            entityTable.setKeyColumns(entityColumn.getColumn());
        } else if (keySql.dialect() == IdentityDialect.DEFAULT) {
            entityColumn.setIdentity(true);
            entityColumn.setOrder(ORDER.AFTER);
        }  else if (keySql.dialect() != IdentityDialect.NULL) {
            //自動增長
            entityColumn.setIdentity(true);
            entityColumn.setOrder(ORDER.AFTER);
            entityColumn.setGenerator(keySql.dialect().getIdentityRetrievalStatement());
        } else if (StringUtil.isNotEmpty(keySql.sql())){

            entityColumn.setIdentity(true);
            entityColumn.setOrder(keySql.order());
            entityColumn.setGenerator(keySql.sql());
        } else if (keySql.genSql() != GenSql.NULL.class){
            entityColumn.setIdentity(true);
            entityColumn.setOrder(keySql.order());
            try {
                GenSql genSql = keySql.genSql().newInstance();
                entityColumn.setGenerator(genSql.genSql(entityTable, entityColumn));
            } catch (Exception e) {
                log.error("例項化 GenSql 失敗: " + e, e);
                throw new MapperException("例項化 GenSql 失敗: " + e, e);
            }
        } else if(keySql.genId() != GenId.NULL.class){
            entityColumn.setIdentity(false);
            entityColumn.setGenIdClass(keySql.genId());
        } else {
            throw new MapperException(entityTable.getEntityClass().getCanonicalName()
                    + " 類中的 @KeySql 註解配置無效!");
        }
    }

}

這裡面就是一些判斷邏輯。於是我們用註解就可以實現了。

以上文章就是記錄一下自己的心得,有不正之處,希望大家多多指點。

相關文章