Oinone引入搜索引擎(增强模型)

场景描述

在碰到大数据量并且需要全文检索的场景,我们在分布式架构中基本会架设ElasticSearch来作为一个常规解决方案。在oinone体系中增强模型就是应对这类场景,其背后也是整合了ElasticSearch;

使用前你应该

  • 了解ElasticSearch,包括不限于:Index(索引)、分词、Node(节点)、Document(文档)、Shards(分片) & Replicas(副本)。参考官方网站:https://www.elastic.co/cn/
  • 有一个可用的ElasticSearch环境(本地项目能引用到)

前置约束

增强模型增量依赖数据变更实时消息,因此确保项目的event是开启的,mq配置正确。

项目引入搜索步骤

1、boot工程加入相关依赖包

  • boot工程需要指定ES客户端包版本,不指定版本会隐性依赖顶层spring-boot依赖管理指定的低版本
  • boot工程加入pamris-channel的工程依赖
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>8.4.1</version>
</dependency>
<dependency>
    <groupId>jakarta.json</groupId>
    <artifactId>jakarta.json-api</artifactId>
    <version>2.1.1</version>
</dependency>

<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-sql-record-core</artifactId>
</dependency>
<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-channel-core</artifactId>
</dependency>

2、api工程加入相关依赖包

在XXX-api中增加入pamirs-channel-api的依赖

<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-channel-api</artifactId>
</dependency>

3、yml文件配置

在pamirs-demo-boot的application-dev.yml文件中增加配置pamirs.boot.modules增加channel,即在启动模块中增加channel模块。同时注意es的配置,是否跟es的服务一致

pamirs:
  record:
    sql:
      #改成自己本地路径(或服务器路径)
      store: /Users/oinone/record
  boot:
    modules:
      - channel
      ## 确保也安装了sql_record
      - sql_record
  channel:
    packages:
      # 增强模型扫描包配置
      - com.xxx.xxx
  elastic:
    url: 127.0.0.1:9200

4、项目的模块增加模块依赖

XXXModule增加对ChannelModule的依赖

@Module(dependencies = {ChannelModule.MODULE_MODULE})

5、增加增强模型(举例)

package pro.shushi.pamirs.demo.api.enhance;

import pro.shushi.pamirs.channel.enmu.IncrementEnum;
import pro.shushi.pamirs.channel.meta.Enhance;
import pro.shushi.pamirs.channel.meta.EnhanceModel;
import pro.shushi.pamirs.demo.api.model.ShardingModel;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;

@Model(displayName = "测试EnhanceModel")
@Model.model(ShardingModelEnhance.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY, inherited = {EnhanceModel.MODEL_MODEL})
@Enhance(shards = "3", replicas = "1", reAlias = true,increment= IncrementEnum.OPEN)
public class ShardingModelEnhance extends ShardingModel {
    public static final String MODEL_MODEL="demo.ShardingModelEnhance";
}

6、重启系统看效果

1、进入【传输增强模型】应用,访问增强模型列表我们会发现一条记录,并点击【全量同步】初始化ES,并全量dump数据
Oinone引入搜索引擎(增强模型)

2、再次回到Demo应用,进入增强模型页面,可以正常访问并进增删改查操作
Oinone引入搜索引擎(增强模型)

个性化dump逻辑

通常dump逻辑是有个性化需求,那么我们可以重写模型的synchronize方法,函数重写特性在“面向对象-继承与多态”部分中已经有详细介绍。

重写ShardingModelEnhance模型的synchronize方法

重写后,如果针对老数据记录需要把新增的字段都自动填充,可以进入【传输增强模型】应用,访问增强模型列表,找到对应的记录并点击【全量同步】

package pro.shushi.pamirs.demo.api.enhance;

import pro.shushi.pamirs.channel.enmu.IncrementEnum;
import pro.shushi.pamirs.channel.meta.Enhance;
import pro.shushi.pamirs.channel.meta.EnhanceModel;
import pro.shushi.pamirs.demo.api.model.ShardingModel;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;

import java.util.List;

@Model(displayName = "测试EnhanceModel")
@Model.model(ShardingModelEnhance.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY, inherited = {EnhanceModel.MODEL_MODEL})
@Enhance(shards = "3", replicas = "1", reAlias = true,increment= IncrementEnum.OPEN)
public class ShardingModelEnhance extends ShardingModel {
    public static final String MODEL_MODEL="demo.ShardingModelEnhance";

    @Field(displayName = "nick")
    private String nick;

    @Function.Advanced(displayName = "同步数据", type = FunctionTypeEnum.UPDATE)
    @Function(summary = "数据同步函数")
    public List<ShardingModelEnhance> synchronize(List<ShardingModelEnhance> data) {
        for(ShardingModelEnhance shardingModelEnhance:data){
            shardingModelEnhance.setNick(shardingModelEnhance.getName());
        }
        return data;
    }
}

给搜索增加个性化逻辑

如果我们需要在查询方法中增加逻辑,在前面的教程中一般是重写queryPage函数,但对于增强模型我们需要重写的是search函数。

个性化search函数

@Function(
        summary = "搜索函数",
        openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API}
)
@pro.shushi.pamirs.meta.annotation.Function.Advanced(
        type = {FunctionTypeEnum.QUERY},
        category = FunctionCategoryEnum.QUERY_PAGE,
        managed = true
)
public  Pagination<ShardingModelEnhance> search(Pagination<ShardingModelEnhance> page, IWrapper<ShardingModelEnhance> queryWrapper) {
    System.out.println("您的个性化搜索逻辑");
    // return ((IElasticRetrieve) CommonApiFactory.getApi(IElasticRetrieve.class)).search(page, queryWrapper);
    return ((ElasticSearchApi) CommonApiFactory.getApi(ElasticSearchApi.class)).search(page, queryWrapper);
}

个性化search函数示例

    @Override
    @SuppressWarnings({"rawtypes"})
    public <T> Pagination<T> search(Pagination<T> page, IWrapper<T> queryWrapper) {
        String modelModel = queryWrapper.getModel();
        if (null == modelModel || modelModel.isEmpty()) {
            return page;
        }
        ModelConfig modelCfg = PamirsSession.getContext().getModelConfig(modelModel);
        if (null == modelCfg) {
            return page;
        }
        String rsql = queryWrapper.getOriginRsql();
        if (StringUtils.isBlank(rsql)) {
            rsql = "id>0";
        }
        BoolQuery.Builder queryBuilder = ElasticRSQLHelper.parseRSQL(modelCfg, rsql);
        TermQuery isDeletedTerm = QueryBuilders.term()
                .queryName(IS_DELETED)
                .field(IS_DELETED).value(0)
                .build();
        BoolQuery.Builder builder = QueryBuilders.bool().must(new Query(queryBuilder.build()));
        builder.must(new Query(isDeletedTerm));
        String alias = IndexNaming.aliasByModel(modelModel);
        Query query = new Query(builder.build());
        log.info("{}", query);

        List<Order> orders = Optional.ofNullable(page.getSort()).map(Sort::getOrders).orElse(new ArrayList<>());
        int currentPage = Optional.ofNullable(page.getCurrentPage()).orElse(1);
        Long size = Optional.ofNullable(page.getSize()).orElse(10L);
        int pageSize = size.intValue();
        List<SortOptions> sortOptions = new ArrayList<>();
        if (CollectionUtils.isEmpty(orders)) {
            orders.add(new Order(SortDirectionEnum.DESC, ID));
            orders.add(new Order(SortDirectionEnum.DESC, CREATE_DATE));
        }
        for (Order order : orders) {
            sortOptions.add(new SortOptions.Builder()
                    .field(SortOptionsBuilders.field()
                            .field(order.getField())
                            .order(SortDirectionEnum.DESC.equals(order.getDirection()) ? SortOrder.Desc : SortOrder.Asc)
                            .build())
                    .build());
        }

        SearchRequest request = new SearchRequest.Builder()
                .index(alias)
                .from((currentPage - 1) * pageSize)
                .size(pageSize)
                .sort(sortOptions)
                .query(query)
                .highlight(_builder ->
                        _builder.numberOfFragments(4)
                                .fragmentSize(50)
                                .type(HighlighterType.Unified)
                                .fields("name", HighlightField.of(_fieldBuilder -> _fieldBuilder.preTags(ElasticsearchConstant.HIGH_LIGHT_PREFIX).postTags(ElasticsearchConstant.HIGH_LIGHT_POSTFIX)))
                                .fields("documentNo", HighlightField.of(_fieldBuilder -> _fieldBuilder.preTags(ElasticsearchConstant.HIGH_LIGHT_PREFIX).postTags(ElasticsearchConstant.HIGH_LIGHT_POSTFIX)))
                                .fields("keywords", HighlightField.of(_fieldBuilder -> _fieldBuilder.preTags(ElasticsearchConstant.HIGH_LIGHT_PREFIX).postTags(ElasticsearchConstant.HIGH_LIGHT_POSTFIX))))
                .build();

        SearchResponse<HashMap> response = null;
        try {
            log.info("ES搜索请求参数:{}", request.toString());
            response = elasticsearchClient.search(request, HashMap.class);
        } catch (ElasticsearchException e) {
            log.error("索引异常", e);
            PamirsSession.getMessageHub()
                    .msg(Message.init()
                            .setLevel(InformationLevelEnum.WARN)
                            .msg("索引异常"));
            return page;
        } catch (IOException e) {
            log.error("ElasticSearch运行状态异常", e);
            PamirsSession.getMessageHub()
                    .msg(Message.init()
                            .setLevel(InformationLevelEnum.WARN)
                            .msg("ElasticSearch运行状态异常"));
            return page;
        }

        if (null == response || response.timedOut()) {
            return page;
        }

        HitsMetadata<HashMap> hits = response.hits();
        if (null == hits) {
            return page;
        }

        TotalHits totalHits = hits.total();
        long total = Optional.ofNullable(totalHits).map(TotalHits::value).orElse(0L);

        List<HashMap> dataMapList = Optional.of(hits)
                .map(HitsMetadata<HashMap>::hits)
                .map(hitsMap ->{
                    hitsMap.stream().forEach(highlightForEach -> {
                        highlightForEach.highlight().forEach((key, value) -> {
                            if(highlightForEach.source().containsKey(key)){
                                highlightForEach.source().put(key,value.get(0));
                            }
                        });

                    });
                    return hitsMap;
                })
                .map(List::stream)
                .orElse(Stream.empty())
                .map(Hit::source)
                .collect(Collectors.toList());

        List<T> context = persistenceDataConverter.out(modelModel, dataMapList);

        page.setSize(size);
        page.setTotalElements(total);
        page.setContent(context);
        log.info("ES搜索请求参数返回total,{}", total);
        return page;
    }

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/7235.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
望闲的头像望闲数式管理员
上一篇 2024年5月14日 pm5:10
下一篇 2024年5月14日 pm10:15

相关推荐

  • 如何跳过固定path路径下面所有的按钮权限

    场景: 业务上需要跳过弹窗打开里面的所有按钮权限。 实践: 实现AuthFilterService权限接口。 package pro.shushi.pamirs.top.api.spi; import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.auth.api.spi.AuthFilterService; import pro.shushi.pamirs.boot.web.session.AccessResourceInfoSession; import pro.shushi.pamirs.meta.common.spi.SPI; /** * @author Yexiu at 09:04 on 2024/9/27 */ @Order(88) @Component @SPI.Service public class CustomAuthFilterService implements AuthFilterService { public static final String skipPath = "/top_demo/uiMenuc6238c29bca44250a041691565056a63/ACTION#top.Teacher#uiView2b60cc6daa334c7280cb78207d41addc"; @Override public Boolean isAccessAction(String model, String name) { String path = AccessResourceInfoSession.getInfo().getOriginPath(); if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } @Override public Boolean isAccessAction(String path) { if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } } 可以看到弹窗下面的按钮都不需要权限控制了。

    2025年3月11日
    82000
  • 框架之MessageHub(信息提示)

    框架之信息概述 后端除了可以返回错误信息以外,还可以返回调试、告警、成功、信息等级别的信息给前端。但是默认情况下前端只提示错误信息,可以通过前端的统一配置放开提示级别,有点类似后端的日志级别。 框架之MessageHub 在oinone平台中,我们怎么做到友好的错误提示呢?接下来介绍我们的MessageHub,它为自定义错误提示提供无限的可能。 何时使用 错误提示是用户体验中特别重要的组成部分,大部分的错误体现在整页级别,字段级别,按钮级别。友好的错误提示应该是怎么样的呢?我们假设他是这样的 与用户操作精密契合 当字段输入异常时,错误展示在错误框底部 按钮触发服务时异常,错误展示在按钮底部 区分不同的类型 错误 成功 警告 提示 调试 简洁易懂的错误信息 不同信息类型的举例 package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetCatItem; import pro.shushi.pamirs.demo.api.model.PetType; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.api.dto.common.Message; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.InformationLevelEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Model.model(PetType.MODEL_MODEL) @Component public class PetTypeAction { @Action(displayName = "消息",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.CONTEXT_FREE) public PetType message(PetType data){ PamirsSession.getMessageHub().info("info1"); PamirsSession.getMessageHub().info("info2"); PamirsSession.getMessageHub().error("error1"); PamirsSession.getMessageHub().error("error2"); PamirsSession.getMessageHub().msg(new Message().msg("success1").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("success2").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("debug1").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("debug2").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("warn1").setLevel(InformationLevelEnum.WARN)); PamirsSession.getMessageHub().msg(new Message().msg("warn2").setLevel(InformationLevelEnum.WARN)); return data; } } 查询运行返回和效果 1)系统提示的返回结果 2)系统提示示例效果

    2024年5月14日
    1.4K00
  • 推送自定义消息

    项目中添加消息依赖 pro.shushi.pamirs.core pamirs-message-api 调用pro.shushi.pamirs.message.engine.message.MessageSender#sendSystemMail发送系统消息示例: @Action(displayName = "发送消息") public Student sendMessage(Student data){ MessageSender mailSender = (MessageSender) MessageEngine.get(MessageEngineTypeEnum.MAIL_SEND).get(null); String content = "发送自定义消息"; String subject = null; List<Long> userIds = new ArrayList<>(); userIds.add(PamirsSession.getUserId()); PamirsMessage message = new PamirsMessage() .setName(subject) .setSubject(subject) .setBody(content) .setMessageType(MessageTypeEnum.NOTIFICATION); List<PamirsMessage> messages = new ArrayList<>(); messages.add(message); SystemMessage systemMessage = new SystemMessage(); systemMessage.setPartners(userIds.stream().map(i -> (PamirsUser) new PamirsUser().setId(i)).collect(Collectors.toList())) .setType(MessageGroupTypeEnum.SYSTEM_MAIL) .setMessages(messages); mailSender.sendSystemMail(systemMessage); return data; }

    2024年8月19日
    1.2K00
  • 自定义数据权限拦截处理

    业务场景 公司给员工对哪些模块有访问权限,这个时候就需要在员工访问模块表的时候做数据过滤, 解决方案 我们可以通过平台提供的数据过滤占位符解决这个问题,新建一条数据行权限,过滤语句条件是占位符,再编写占位符的解析逻辑 1.初始化权限基础数据 package pro.shushi.pamirs.demo.core.init; import com.google.common.collect.Lists; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.auth.api.constants.AuthConstants; import pro.shushi.pamirs.auth.api.enmu.AuthGroupTypeEnum; import pro.shushi.pamirs.auth.api.enmu.PermissionDataSourceEnum; import pro.shushi.pamirs.auth.api.enmu.PermissionTypeEnum; import pro.shushi.pamirs.auth.api.model.AuthGroup; import pro.shushi.pamirs.auth.api.model.AuthRole; import pro.shushi.pamirs.auth.api.model.ResourcePermission; import pro.shushi.pamirs.boot.base.model.UeModule; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.api.init.InstallDataInit; import pro.shushi.pamirs.boot.common.api.init.UpgradeDataInit; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.demo.core.placeholder.EmployeeModulePlaceholder; import pro.shushi.pamirs.framework.common.utils.ObjectUtils; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.domain.module.ModuleDefinition; import java.util.Collections; import java.util.List; @Slf4j @Component @Order(0) public class DemoModuleBizInit implements InstallDataInit, UpgradeDataInit { @Override public List<String> modules() { return Collections.singletonList(DemoModule.MODULE_MODULE); } @Override public int priority() { return 0; } @Override public boolean init(AppLifecycleCommand command, String version) { this.initAuth(); return true; } @Override public boolean upgrade(AppLifecycleCommand command, String version, String existVersion) { this.initAuth(); return true; } private void initAuth() { AuthGroup authGroup = new AuthGroup(); authGroup.setName("测试权限组") .setDisplayName("测试权限组") .setType(AuthGroupTypeEnum.RUNTIME) .setActive(true); authGroup.createOrUpdate(); AuthRole authRole = new AuthRole(); authRole.setCode("TEST_ROLE_1") .setName("测试角色") .setRoleTypeCode(AuthConstants.ROLE_SYSTEM_TYPE_CODE) .setPermissionDataSource(PermissionDataSourceEnum.CUSTOM) .setActive(true); authRole.createOrUpdate(); authRole.setGroups(Lists.newArrayList(authGroup)); authRole.fieldSave(AuthRole::getGroups); ResourcePermission authPermission = new ResourcePermission(); authPermission.setName("测试模块权限过滤") .setDomainExp(EmployeeModulePlaceholder.PLACEHOLDER) .setModel(ModuleDefinition.MODEL_MODEL) .setPermRead(true) .setPermRun(true) .setPermissionType(PermissionTypeEnum.ROW) .setPermissionDataSource(PermissionDataSourceEnum.CUSTOM) .setCanShow(true) .setActive(true); ResourcePermission authPermission2 = ObjectUtils.clone(authPermission); authPermission2.setName("测试ue模块权限过滤").setModel(UeModule.MODEL_MODEL); authGroup.setPermissions(Lists.newArrayList(authPermission, authPermission2)); authGroup.fieldSave(AuthGroup::getPermissions); } } 这里演示的module表比较特殊,需要同时设置ModuleDefinition和UeModule这2个模型做数据过滤 2.编写占位符拦截替换逻辑 package pro.shushi.pamirs.demo.core.placeholder; import org.springframework.stereotype.Component; import pro.shushi.pamirs.user.api.AbstractPlaceHolderParser; @Component public class EmployeeModulePlaceholder extends AbstractPlaceHolderParser { public static final String PLACEHOLDER = "${employeeModulePlaceholder}"; protected String value() { // TODO…

    2023年11月24日
    1.1K00
  • 【OpenGauss】后端部署使用OpenGauss高斯数据库

    Gauss数据库配置 适配版本 4.7.8.3之后的版本 配置步骤 Maven配置 去华为官网下周驱动包:gsjdbc4.jar;https://support.huaweicloud.com/mgtg-dws/dws_01_0032.html <dependency> <groupId>org.postgresql</groupId> <artifactId>gsjdbc</artifactId> <version>4</version> <scope>system</scope> <!– 下面两种方式都可以–> <systemPath>${pom.basedir}/libs/gsjdbc4.jar</systemPath> <!–<systemPath>/Users/wangxian/java-tools/guassdb/gsjdbc4.jar</systemPath>–> </dependency> 导入 scope 为 system 的包,spring 编译插件需要增加 includeSystemScope: true 配置。 <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeSystemScope>true</includeSystemScope> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> JDBC连接配置 pamirs: datasource: pamirs: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/pamirs?currentSchema=demo username: XXXXXX password: XXXXXX initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/pamirs?currentSchema=demo_base username: XXXXXX password: XXXXXX initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 连接url配置 点击查看官方文档:官方文档 url格式 jdbc:postgresql://${host}:${port}/${database}?currentSchema=${schema} 在pamirs连接配置时,${database}和${schema}必须完整配置,不可缺省。 其他连接参数如需配置,可自行查阅相关资料进行调优。 方言配置 pamirs方言配置 pamirs: dialect: ds: base: type: GaussDB version: 5 majorVersion: 5.0.1 pamirs: type: GaussDB version: 5 majorVersion: 5.0.1 数据库版本 type version majorVersion 5.x GaussDB 5 5.0.1 PS:由于方言开发环境为5.0.1版本,其他类似版本(5.x)原则上不会出现太大差异,如出现其他版本无法正常支持的,可在文档下方留言。 schedule方言配置 pamirs: event: enabled: true schedule: enabled: true dialect: type: GaussDB version: 5 major-version: 5.0.1 type version majorVersion GaussDB 5 5.0.1 PS:由于schedule的方言在多个版本中并无明显差异,目前仅提供一种方言配置。 其他配置 逻辑删除的值配置 pamirs: mapper: global: table-info: logic-delete-value: (EXTRACT(epoch FROM CURRENT_TIMESTAMP) * 1000000 + EXTRACT(MICROSECONDS FROM CURRENT_TIMESTAMP))::bigint Gauss数据库用户初始化及授权 — init root…

    2024年3月27日
    2.2K00

Leave a Reply

登录后才能评论