seata适配人大金仓(kingbase8)数据库

seata适配人大金仓(kingbase8)数据库

一、seata源码环境准备

二、seata源码环境编译

使用idea开发工具,打开你下载好的seata源码,并下载好相关jar包依赖。
编译好的源码环境如下:

  • 在这里插入图片描述

三、seata适配kingbase8

注意:
如果想适配dm达梦数据库,由于undo_log表会出现context关键字问题,所以这里得改下这个字段,改成context_即可。

io.seata.core.constants.ClientTableColumnsName.java

String UNDO_LOG_CONTEXT = "context_";

注意,改了之后,对应的sql语句,也记得修改下。

3.1 seata-core的修改

增加io.seata.core.store.db.sql.lock.KingbaseLockStoreSql.java
注意:KingbaseLockStoreSql.java,继承OracleLockStoreSql.java

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.core.store.db.sql.lock.LockStoreSql

  • 在这里插入图片描述

增加io.seata.core.store.db.sql.log.KingBaseLogStoreSqls.java
注意:KingBaseLogStoreSqls.java,继承OracleLogStoreSqls.java

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.core.store.db.sql.log.LogStoreSqls

  • 在这里插入图片描述

io.seata.core.constants.DBType.java 增加 kingbase

  • 在这里插入图片描述

修改io.seata.core.store.db.AbstractDataSourceProvider.java,getValidationQuery()方法
支持kingbase的类型

  • 在这里插入图片描述
3.2 seata-sqlparser-core修改

修改io.seata.sqlparser.util.JdbcConstants.java , 增加kingbase常量

  • 在这里插入图片描述
3.3 seata-sqlparser-druid修改

io.seata.sqlparser.druid–>增加kingbase包以及内部的java,模仿oracle的即可。
注意:需要修改的地方有:
(1)常量JdbcConstants.KINGBASE
(2)构造方法

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.sqlparser.druid.SQLOperateRecognizerHolder

  • 在这里插入图片描述
3.4 seata-rm-datasource的修改

增加io.seata.rm.datasource.exec.kingbase.KingbaseInsertExecutor.java
注意:KingbaseInsertExecutor.java,模仿OracleInsertExecutor.java

  • 在这里插入图片描述

代码如下:

/*
 *  Copyright 1999-2019 Seata.io Group.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package io.seata.rm.datasource.exec.kingbase;

import io.seata.common.exception.NotSupportYetException;
import io.seata.common.loader.LoadLevel;
import io.seata.common.loader.Scope;
import io.seata.rm.datasource.StatementProxy;
import io.seata.rm.datasource.exec.BaseInsertExecutor;
import io.seata.rm.datasource.exec.StatementCallback;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.struct.Null;
import io.seata.sqlparser.struct.Sequenceable;
import io.seata.sqlparser.struct.SqlMethodExpr;
import io.seata.sqlparser.struct.SqlSequenceExpr;
import io.seata.sqlparser.util.JdbcConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author llsydn
 */
@LoadLevel(name = JdbcConstants.KINGBASE, scope = Scope.PROTOTYPE)
public class KingbaseInsertExecutor extends BaseInsertExecutor implements Sequenceable {

    private static final Logger LOGGER = LoggerFactory.getLogger(KingbaseInsertExecutor.class);

    /**
     * Instantiates a new Abstract dml base executor.
     *
     * @param statementProxy    the statement proxy
     * @param statementCallback the statement callback
     * @param sqlRecognizer     the sql recognizer
     */
    public KingbaseInsertExecutor(StatementProxy statementProxy, StatementCallback statementCallback,
                                  SQLRecognizer sqlRecognizer) {
        super(statementProxy, statementCallback, sqlRecognizer);
    }

    @Override
    public Map<String,List<Object>> getPkValues() throws SQLException {
        Map<String,List<Object>> pkValuesMap = null;
        Boolean isContainsPk = containsPK();
        //when there is only one pk in the table
        if (isContainsPk) {
            pkValuesMap = getPkValuesByColumn();
        }
        else if (containsColumns()) {
            String columnName = getTableMeta().getPrimaryKeyOnlyName().get(0);
            pkValuesMap = Collections.singletonMap(columnName, getGeneratedKeys());
        }
        else {
            pkValuesMap = getPkValuesByColumn();
        }
        return pkValuesMap;
    }

    @Override
    public Map<String,List<Object>> getPkValuesByColumn() throws SQLException {
        Map<String,List<Object>> pkValuesMap  = parsePkValuesFromStatement();
        String pkKey = pkValuesMap.keySet().iterator().next();
        List<Object> pkValues = pkValuesMap.get(pkKey);

        if (!pkValues.isEmpty() && pkValues.get(0) instanceof SqlSequenceExpr) {
            pkValuesMap.put(pkKey,getPkValuesBySequence((SqlSequenceExpr) pkValues.get(0)));
        } else if (pkValues.size() == 1 && pkValues.get(0) instanceof SqlMethodExpr) {
            pkValuesMap.put(pkKey,getGeneratedKeys());
        } else if (pkValues.size() == 1 && pkValues.get(0) instanceof Null) {
            throw new NotSupportYetException("oracle not support null");
        }

        return pkValuesMap;
    }

    @Override
    public String getSequenceSql(SqlSequenceExpr expr) {
        return "SELECT " + expr.getSequence() + ".currval FROM DUAL";
    }
}

加入到配置文件:META-INF/services/io.seata.rm.datasource.exec.InsertExecutor

  • 在这里插入图片描述

增加io.seata.rm.datasource.sql.struct.cache.KingbaseTableMetaCache.java
注意:KingbaseTableMetaCache.java,模仿OracleTableMetaCache.java

  • 在这里插入图片描述

代码如下:

/*
 *  Copyright 1999-2019 Seata.io Group.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package io.seata.rm.datasource.sql.struct.cache;

import io.seata.common.exception.ShouldNeverHappenException;
import io.seata.common.loader.LoadLevel;
import io.seata.common.util.StringUtils;
import io.seata.rm.datasource.sql.struct.ColumnMeta;
import io.seata.rm.datasource.sql.struct.IndexMeta;
import io.seata.rm.datasource.sql.struct.IndexType;
import io.seata.rm.datasource.sql.struct.TableMeta;
import io.seata.sqlparser.util.JdbcConstants;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * The type Table meta cache.
 *
 * @author llsydn
 */
@LoadLevel(name = JdbcConstants.KINGBASE)
public class KingbaseTableMetaCache extends AbstractTableMetaCache {

    @Override
    protected String getCacheKey(Connection connection, String tableName, String resourceId) {
        StringBuilder cacheKey = new StringBuilder(resourceId);
        cacheKey.append(".");

        //separate it to schemaName and tableName
        String[] tableNameWithSchema = tableName.split("\\.");
        String defaultTableName = tableNameWithSchema.length > 1 ? tableNameWithSchema[1] : tableNameWithSchema[0];

        //oracle does not implement supportsMixedCaseIdentifiers in DatabaseMetadata
        if (defaultTableName.contains("\"")) {
            cacheKey.append(defaultTableName.replace("\"", ""));
        } else {
            // oracle default store in upper case
            cacheKey.append(defaultTableName.toUpperCase());
        }

        return cacheKey.toString();
    }

    @Override
    protected TableMeta fetchSchema(Connection connection, String tableName) throws SQLException {
        try {
            return resultSetMetaToSchema(connection.getMetaData(), tableName);
        } catch (SQLException sqlEx) {
            throw sqlEx;
        } catch (Exception e) {
            throw new SQLException(String.format("Failed to fetch schema of %s", tableName), e);
        }
    }

    private TableMeta resultSetMetaToSchema(DatabaseMetaData dbmd, String tableName) throws SQLException {
        TableMeta tm = new TableMeta();
        tm.setTableName(tableName);
        String[] schemaTable = tableName.split("\\.");
        String schemaName = schemaTable.length > 1 ? schemaTable[0] : dbmd.getUserName();
        tableName = schemaTable.length > 1 ? schemaTable[1] : tableName;
        if (schemaName.contains("\"")) {
            schemaName = schemaName.replace("\"", "");
        } else {
            schemaName = schemaName.toUpperCase();
        }

        schemaName="PUBLIC";

        if (tableName.contains("\"")) {
            tableName = tableName.replace("\"", "");

        } else {
            tableName = tableName.toUpperCase();
        }

        try (ResultSet rsColumns = dbmd.getColumns("", schemaName, tableName, "%");
             ResultSet rsIndex = dbmd.getIndexInfo(null, schemaName, tableName, false, true);
             ResultSet rsPrimary = dbmd.getPrimaryKeys(null, schemaName, tableName)) {
            while (rsColumns.next()) {
                ColumnMeta col = new ColumnMeta();
                col.setTableCat(rsColumns.getString("TABLE_CAT"));
                col.setTableSchemaName(rsColumns.getString("TABLE_SCHEM"));
                col.setTableName(rsColumns.getString("TABLE_NAME"));
                col.setColumnName(rsColumns.getString("COLUMN_NAME"));
                col.setDataType(rsColumns.getInt("DATA_TYPE"));
                col.setDataTypeName(rsColumns.getString("TYPE_NAME"));
                col.setColumnSize(rsColumns.getInt("COLUMN_SIZE"));
                col.setDecimalDigits(rsColumns.getInt("DECIMAL_DIGITS"));
                col.setNumPrecRadix(rsColumns.getInt("NUM_PREC_RADIX"));
                col.setNullAble(rsColumns.getInt("NULLABLE"));
                col.setRemarks(rsColumns.getString("REMARKS"));
                col.setColumnDef(rsColumns.getString("COLUMN_DEF"));
                col.setSqlDataType(rsColumns.getInt("SQL_DATA_TYPE"));
                col.setSqlDatetimeSub(rsColumns.getInt("SQL_DATETIME_SUB"));
                col.setCharOctetLength(rsColumns.getInt("CHAR_OCTET_LENGTH"));
                col.setOrdinalPosition(rsColumns.getInt("ORDINAL_POSITION"));
                col.setIsNullAble(rsColumns.getString("IS_NULLABLE"));

                tm.getAllColumns().put(col.getColumnName(), col);
            }

            while (rsIndex.next()) {
                String indexName = rsIndex.getString("INDEX_NAME");
                if (StringUtils.isNullOrEmpty(indexName)) {
                    continue;
                }
                String colName = rsIndex.getString("COLUMN_NAME");
                ColumnMeta col = tm.getAllColumns().get(colName);
                if (tm.getAllIndexes().containsKey(indexName)) {
                    IndexMeta index = tm.getAllIndexes().get(indexName);
                    index.getValues().add(col);
                } else {
                    IndexMeta index = new IndexMeta();
                    index.setIndexName(indexName);
                    index.setNonUnique(rsIndex.getBoolean("NON_UNIQUE"));
                    index.setIndexQualifier(rsIndex.getString("INDEX_QUALIFIER"));
                    index.setIndexName(rsIndex.getString("INDEX_NAME"));
                    index.setType(rsIndex.getShort("TYPE"));
                    index.setOrdinalPosition(rsIndex.getShort("ORDINAL_POSITION"));
                    index.setAscOrDesc(rsIndex.getString("ASC_OR_DESC"));
                    index.setCardinality(rsIndex.getInt("CARDINALITY"));
                    index.getValues().add(col);
                    if (!index.isNonUnique()) {
                        index.setIndextype(IndexType.UNIQUE);
                    } else {
                        index.setIndextype(IndexType.NORMAL);
                    }
                    tm.getAllIndexes().put(indexName, index);

                }
            }

            while (rsPrimary.next()) {
                String pkIndexName = rsPrimary.getString("PK_NAME");
                if (tm.getAllIndexes().containsKey(pkIndexName)) {
                    IndexMeta index = tm.getAllIndexes().get(pkIndexName);
                    index.setIndextype(IndexType.PRIMARY);
                }
                else {
                    String colName = rsPrimary.getString("COLUMN_NAME");
                    ColumnMeta col = tm.getAllColumns().get(colName);
                    IndexMeta index = new IndexMeta();
                    index.getValues().add(col);
                    index.setIndextype(IndexType.PRIMARY);
                    tm.getAllIndexes().put(pkIndexName, index);
                }
            }
            if (tm.getAllIndexes().isEmpty()) {
                throw new ShouldNeverHappenException(String.format("Could not found any index in the table: %s", tableName));
            }
        }

        return tm;
    }
}

加入到配置文件中:META-INF/services/io.seata.rm.datasource.sql.struct.TableMetaCache

  • 在这里插入图片描述

io.seata.rm.datasource.undo–>增加kingbase包以及内部的java,模仿oracle的即可。
注意:需要修改的地方有:
(1)常量JdbcConstants.KINGBASE
(2)构造方法

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.rm.datasource.undo.KeywordChecker

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.rm.datasource.undo.UndoLogManager

  • 在这里插入图片描述

加入到配置文件中:META-INF/services/io.seata.rm.datasource.undo.UndoExecutorHolder

  • 在这里插入图片描述

四、seata修改ip有效性校验

seata在启动时,会对 “-h ip” 进行有效性校验,并且 “127.0.0.1 and 0.0.0.0” 也是校验不通过的
在docker容器、需要注册到外网ip、需要注册到域名,那都是校验失败的
所以这里对源码进行修改,seata启动时,不校验ip的有效性。

修改io.seata.server.Server.java,main()方法

  • 在这里插入图片描述

五、修改后seata源码打包

右键:pom.xml,选择Run Maven --> New Goal --> -Dmaven.test.skip=true -Dcheckstyle.skip=true clean install -U

  • 在这里插入图片描述
  • 在这里插入图片描述
  • 在这里插入图片描述

打包成功后,是放在seata-distribution下面,直接就是和在官网下载的seata服务一样的文件

  • 在这里插入图片描述

这里要注意:要将kingbase8的驱动jar包,手动拷贝放入到lib下面。

  • 在这里插入图片描述

至此:seata的适配kingbase8,并重新打包源码,已完成

  • seata配合nacos使用,需要修改的配置如下:

store.db.url = jdbc:kingbase8://xxx.xxx.x.xx:54321/db1
store.db.driverClassName = com.kingbase8.Driver
store.db.dbType = kingbase
store.db.user = root
store.db.password = 123456

六、项目中使用seata

  • 在项目中需要引入seata相关得依赖
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
	<version>1.4.1.1</version>
</dependency>

<dependency>
     <groupId>io.seata</groupId>
     <artifactId>seata-spring-boot-starter</artifactId>
	<version>1.4.1.1</version>
</dependency>

配置文件:

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: llsydn_tx_group
  enable-auto-data-source-proxy: true

  registry:
    type: nacos
    nacos:
      application: seata-server
      namespace: ${nacos.namespace}
      server-addr: ${nacos.address}
      group : DEFAULT_GROUP
      userName: ${nacos.username}
      password: ${nacos.password}

  config:
    type: nacos
    nacos:
      namespace: ${nacos.namespace}
      serverAddr: ${nacos.address}
      group: SEATA_GROUP
      cluster: default
      userName: ${nacos.username}
      password: ${nacos.password}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

llsydn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值