1. 概述

SEATA 默认支持mysql,oracle,postgresql 等数据库,在软件国产化当下,支持国产数据库也是必须的。因此我们需要支持国产数据库。好在 seata 提供了比较好的扩展方式支持我们去扩展。扩展应该包括两块:
1.TC的扩展。
2.RM 客户端的扩展。

2. 扩展的整体思路

TC说的是seata-server,在源码中我们可以看到:

入口程序是Server 类。

2.1 构建数据源

private DataBaseTransactionStoreManager() {
        logQueryLimit = CONFIG.getInt(ConfigurationKeys.STORE_DB_LOG_QUERY_LIMIT, DEFAULT_LOG_QUERY_LIMIT);
        String datasourceType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE);
        //init dataSource
        DataSource logStoreDataSource = EnhancedServiceLoader.load(DataSourceProvider.class, datasourceType).provide();
        logStore = new LogStoreDataBaseDAO(logStoreDataSource);
    }

加载数据源类:

@LoadLevel(name = "druid")
public class DruidDataSourceProvider extends AbstractDataSourceProvider {

    @Override
    public DataSource generate() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(getDriverClassName());
        ds.setDriverClassLoader(getDriverClassLoader());
        ds.setUrl(getUrl());
        ds.setUsername(getUser());
        ds.setPassword(getPassword());
        ds.setInitialSize(getMinConn());
        ds.setMaxActive(getMaxConn());
        ds.setMinIdle(getMinConn());
        ds.setMaxWait(getMaxWait());
        ds.setTimeBetweenEvictionRunsMillis(120000);
        ds.setMinEvictableIdleTimeMillis(300000);
        ds.setTestWhileIdle(true);
        ds.setTestOnBorrow(false);
        ds.setPoolPreparedStatements(true);
        ds.setMaxPoolPreparedStatementPerConnectionSize(20);
        ds.setValidationQuery(getValidationQuery(getDBType()));
        ds.setDefaultAutoCommit(true);
        return ds;
    }
}

平台加载根据不同的数据类型加载 LogStoreSqls 对象。

public class LogStoreSqlsFactory {

    private static Map<String, LogStoreSqls> LOG_STORE_SQLS_MAP = new ConcurrentHashMap<>();

    /**
     * get the log store sqls
     * @param dbType the db type
     * @return the LogStoreSqls
     */
    public static LogStoreSqls getLogStoreSqls(String dbType) {
        return CollectionUtils.computeIfAbsent(LOG_STORE_SQLS_MAP, dbType,
            key -> EnhancedServiceLoader.load(LogStoreSqls.class, dbType.toLowerCase()));
    }
}

通过数据库类型获取 LogStoreSqls 接口实现实例。

在平台中我们可以看到 有关LogStoreSqls 的实现。

我们增加一个kingbase 的实现。

@LoadLevel(name = "kingbase" )
public class KingBaseLogStoreSqls extends OracleLogStoreSqls {

}

因为kingbase 的语法和 ORACLE 差不多所以这里我们简单继承一下 OracleLogStoreSqls,另外我们需要对META-INF.service 的 io.seata.core.store.db.sql.log.LogStoreSqls 进行编辑。

锁表类实现

LockStoreSql

@LoadLevel(name = "kingbase")
public class KingbaseLockStoreSql extends OracleLockStoreSql {

}

编辑文件 io.seata.core.store.db.sql.lock.LockStoreSql

通过这些改造,server 端已经可以开始支持kingbase 数据库了。

对kingbase 的支持,我们需要修改 nacos 对于数据库类型的相关配置。

参数 说明
store.db.dbType kingbase
store.db.driverClassName 驱动名称,
store.db.url jdbc:kingbase8://localhost:54321/SEATA
store.db.driverClassName com.kingbase8.Driver

在 server 项目的pom.xml 中增加

<dependency>
<groupId>com.kingbase</groupId>
<artifactId>kingbase8</artifactId>
<version>8.2.0</version>
</dependency>

3. seata1.4.1 AT模式集成人大金仓(kingbase8)以及达梦数据库的支持

3.1 服务端的修改

(1)在core(seata-core)\src\main\resouces\META-INF.services 目录下的两个文件io.seata.core.store.db.sql.lock.LockStoreSql、io.seata.core.store.db.sql.log.LogStoreSqls 分别增加对金仓、达梦的支持。

(2)在core(seata-core)\src\main\java 目录下面增加io.seata.core.store.db.sql.lock.KingbaseLockStoreSql以及io.seata.core.store.db.sql.lock.DmLockStoreSql类,它们分别继承OracleLockStoreSql类。

(3)在core(seata-core)\src\main\java 目录下面增加io.seata.core.store.db.sql.log.KingBaseLogStoreSqls以及io.seata.core.store.db.sql.log.DmLogStoreSqls类,它们分别继承OracleLogStoreSqls类。

(4)修改core(seata-core)\src\main\java 目录下面的io.seata.core.constants.DBType类,增加对人大金仓以及达梦数据库的支持。

(5)修改core(seata-core)\src\main\java 目录下面的io.seata.core.store.db.AbstractDataSourceProvider类,增加对人大金仓以及达梦数据库的支持。

(6)core(seata-core)\src\main\java目录下面的io.seata.core.constants.ClientTableColumnsName类,将其里面的UNDO_LOG_CONTEXT字段的值修改为【context_】,跟数据库的表undo_log的字段context_保持一致。

3.2 客户端的修改

(1)在rm-datasource(seata-rm-datasource)\src\main\resouces\META-INF.services 目录下的5个文件io.seata.rm.datasource.exec.InsertExecutor、io.seata.rm.datasource.sql.struct.TableMetaCache、io.seata.rm.datasource.undo.KeywordChecker、io.seata.rm.datasource.undo.UndoExecutorHolder、io.seata.rm.datasource.undo.UndoLogManager 分别增加对金仓、达梦的支持

(2)InsertExecutor的扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.exec.oracle.OracleInsertExecutor,分别增加io.seata.rm.datasource.exec.kingbase.KingbaseInsertExecutor类,io.seata.rm.datasource.exec.dm.DmInsertExecutor类。

(3)TableMetaCache的扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.sql.struct.cache.OracleTableMetaCache,分别增加io.seata.rm.datasource.sql.struct.cache.KingbaseTableMetaCache类,io.seata.rm.datasource.sql.struct.cache.DmTableMetaCache类。

(4)KeywordChecker的扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.sql.struct.cache.OracleTableMetaCache,分别增加io.seata.rm.datasource.sql.struct.cache.KingbaseTableMetaCache类,io.seata.rm.datasource.sql.struct.cache.DmTableMetaCache类。

(5)UndoExecutorHolder的扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.undo.oracle.OracleUndoExecutorHolder,分别增加io.seata.rm.datasource.undo.kingbase.KingbaseUndoExecutorHolder类,io.seata.rm.datasource.undo.dm.DmUndoExecutorHolder类。

(6)UndoExecutorHolder的insert扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.undo.oracle.OracleUndoInsertExecutor,分别增加io.seata.rm.datasource.undo.kingbase.KingbaseUndoInsertExecutor类,io.seata.rm.datasource.undo.dm.DmUndoInsertExecutor类。

(7)UndoExecutorHolder的update扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.undo.oracle.OracleUndoUpdateExecutor,分别增加io.seata.rm.datasource.undo.kingbase.KingbaseUndoUpdateExecutor类,io.seata.rm.datasource.undo.dm.DmUndoUpdateExecutor类。

(8)UndoExecutorHolder的delete扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.undo.oracle.OracleUndoDeleteExecutor,分别增加io.seata.rm.datasource.undo.kingbase.KingbaseUndoDeleteExecutor类,io.seata.rm.datasource.undo.dm.DmUndoDeleteExecutor类。

(9)UndoLogManager的扩展,在rm-datasource(seata-rm-datasource)\src\main\java 目录下面模仿io.seata.rm.datasource.undo.oracle.OracleUndoLogManager,分别增加io.seata.rm.datasource.undo.kingbase.KingbaseUndoLogManager类,io.seata.rm.datasource.undo.dm.DmUndoLogManager类。

(10)在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\resouces\META-INF.services 目录下的io.seata.sqlparser.druid.SQLOperateRecognizerHolder 增加对金仓、达梦的支持

(11)SQLOperateRecognizerHolder的扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder,分别增加io.seata.sqlparser.druid.kingbase.KingbaseOperateRecognizerHolder类,io.seata.sqlparser.druid.dm.DmOperateRecognizerHolder类。

(12)SQLOperateRecognizerHolder的base扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.BaseOracleRecognizer,分别增加io.seata.sqlparser.druid.kingbase.BaseKingbaseRecognizer类,io.seata.sqlparser.druid.dm.BaseDmRecognizer类。

(13)SQLOperateRecognizerHolder的insert扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.OracleInsertRecognizer,分别增加io.seata.sqlparser.druid.kingbase.KingbaseInsertRecognizer类,io.seata.sqlparser.druid.dm.DmInsertRecognizer类。

(14)SQLOperateRecognizerHolder的update扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.OracleUpdateRecognizer,分别增加io.seata.sqlparser.druid.kingbase.KingbaseUpdateRecognizer类,io.seata.sqlparser.druid.dm.DmUpdateRecognizer类。

(15)SQLOperateRecognizerHolder的delete扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.OracleDeleteRecognizer,分别增加io.seata.sqlparser.druid.kingbase.KingbaseDeleteRecognizer类,io.seata.sqlparser.druid.dm.DmDeleteRecognizer类。

(16)SQLOperateRecognizerHolder的selectForUpdate扩展,在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下面模仿io.seata.sqlparser.druid.oracle.OracleSelectForUpdateRecognizer,分别增加io.seata.sqlparser.druid.kingbase.KingbaseSelectForUpdateRecognizer类,io.seata.sqlparser.druid.dm.DmSelectForUpdateRecognizer类。

4. 对微服务端jar包进行修改

在微服务端,我们使用的是打包后的 seat-all 的数据。

5. 其它扩展

5.1 对变更表结构(如增加字段)的扩展支持

seata中表结构会缓存一段时间,变更了表结构缓存还没有失效。导致不一致报错。默认配置下,表结构缓存为10多分钟能够恢复正常。
因此,需对源码进行修改。在rm-datasource(seata-rm-datasource)\src\main\java 目录下,对io.seata.rm.datasource.sql.struct.TableRecords类进行修改,如下图所示:

对buildRecords方法里面的相关代码进行微调,columnName以及dataType不再从缓存的表结构TableMeta获取,改从ResultSetMetaData中获取。

5.2 对多表关联更新的扩展支持

seata默认不支持多表关联更新,需对源码进行修改。

在rm-datasource(seata-rm-datasource)\src\main\java 目录下,对io.seata.rm.datasource.exec.UpdateExecutor类进行修改,如下图所示:

5.2.1 mysql数据库

在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下,对io.seata.sqlparser.druid.mysql.MySQLUpdateRecognizer类进行修改,如下图所示:

5.2.2 oracle、kingbase(人大金仓)以及达梦数据库

(1)在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下,对io.seata.sqlparser.druid.oracle.OracleUpdateRecognizer类进行修改,如下图所示:

(2)在sqlparser(seata-sqlparser)的子模块seata-sqlparser-druid\src\main\java 目录下,对io.seata.rm.datasource.undo.oracle.keyword.OracleKeywordChecker类进行修改,如下图所示:

5.2.3 多表关联更新SQL语句样例

(1)mysql数据库:

普通多表连接

update PRODUCT a,PRODUCT_DETAIL b set a.NAME_='测试seata', a.TOTAL_=b.ID_ where a.ID_=b.PRODUCT_ID_ and b.USER_NAME_='李四'

join table

update ORDERS a  join ORDERS_DETAIL b on  a.PRODUCT_ID_=b.ORDERS_ID_ set a.TOTAL_= 1998, a.ID_=12     where b.USER_NAME_='张三'

(2)oracle、kingbase(人大金仓)以及达梦数据库:

update PRODUCT a set a.NAME_='测试seata', a.TOTAL_=(select b.Id_ from PRODUCT_DETAIL b      where a.ID_=b.PRODUCT_ID_ and b.USER_NAME_='李四'
      where exists (select 1 from PRODUCT_DETAIL b where a.ID_=b.PRODUCT_ID_ and       b.USER_NAME_='李四')
文档更新时间: 2021-05-07 18:33   作者:zyg