springcloud集成seata(AT)分布式事务

news2024/11/16 15:49:07

目录

一、 下载seata server和seata源码

二、配置启动seata

2.1 在nacos控制台,新建一个seata的名称空间,用于存放seata的专用配置

2.2 创建seata server的mysql库

2.3 在nacos上配置seata相关配置 (seata名称空间)

2.4 启动seata server

三、springcloud客户端服务集成

 3.1、pom.xml中引入相应依赖包

3.2 、服务的application.yml配置,新增以下配置

四、分布式事务(AT)案例演示


一、 下载seata server和seata源码

alibaba seata  分为server和client(java)两个部分组成,server是独立的jar服务,需要从seata 官网或github下载。

seata官方文档:http://seata.io/zh-cn/docs/user/quickstart.html​ 

seata server下载地址:https://github.com/seata/seata/releases 

笔者下载的是1.6版本 seata-server-1.6.0.zip ,加压缩seata-server-1.6.0.zip ,得到seata-1.6.0目

seata 源代码下载: https://github.com/seata/seata

​git clone  https://github.com/seata/seata
cd seata 
git checkout -b 1.6.0 origin/1.6.0

二、配置启动seata

2.1 在nacos控制台,新建一个seata的名称空间,用于存放seata的专用配置

2.2 创建seata server的mysql库

创建seata的mysql的db:

CREATE DATABASE seata_1.6  DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

找到 seata-1.6\script\server\db\下的mysql.sql文件, 在 seata_1.6   db中执行,生成seata server所需要的表。

2.3 在nacos上配置seata相关配置 (seata名称空间)

在nacos的seata空间下,创建一个seataServer.properties的配置 和service.vgroupMapping.default_tx_group 配置值为default

找到 seata-1.6\script\config-center\config.txt ,修改其中内容(修改前可备份一下文件),将所有配置复制到seataServer.properties中。最终seataServer.properties的配置内容如下:

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
#service.default.grouplist=127.0.0.1:8091

service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=kryo
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=file
store.session.mode=file
#Used for password encryption
store.publicKey=

#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata_1.6?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

(由于笔者的使用的mysql8,jdbc驱动需要修改为com.mysql.cj.jdbc.Driver,  jdbcUrl也需要调整)

2.4 启动seata server

 修改 seata\config\application.yml配置

 
server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata

console:
  user:
    username: seata
    password: seata
  
seata:
  security:
    secretKey: icilfnMRQmKi847ofQUD9UrNaStS9sl0tKlc21s6uSBRbrSldZzVLuPMEfkZZlP3
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
 
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8850
      namespace: seata
      group: DEFAULT_GROUP
      username: nacos
      password: nacos
      context-path: 
      data-id: seataServer.properties
 
      
  registry:
    type: nacos
    #preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8850
      group: DEFAULT_GROUP
      namespace: seata
      cluster: default
      username: nacos
      password: nacos
      context-path:
  server:
    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
    max-commit-retry-timeout: -1
    max-rollback-retry-timeout: -1
    rollback-retry-timeout-unlock-enable: false
    enable-check-auth: true
    enable-parallel-request-handle: true
    retry-dead-threshold: 130000
    xaer-nota-retry-timeout: 60000
    recovery:
      committing-retry-period: 1000
      async-committing-retry-period: 1000
      rollbacking-retry-period: 1000
      timeout-retry-period: 1000
    undo:
      log-save-days: 7
      log-delete-period: 86400000
    session:
      branch-async-queue-size: 5000 #branch async remove queue size
      enable-branch-async-remove: false #enable to asynchronous remove branchSession
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    file:
      dir: sessionStore
      max-branch-session-size: 16384
      max-global-session-size: 512
      file-write-buffer-cache-size: 16384
      session-reload-read-size: 100
      flush-disk-mode: async
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata_1.6?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true&rewriteBatchedStatements=true
      user: root
      password: 123456
      min-conn: 5
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 100
      max-wait: 5000
 
  metrics:
    enabled: false
    registry-type: compact
    exporter-list: prometheus
    exporter-prometheus-port: 9898
  transport:
    rpc-tc-request-timeout: 30000
    enable-tc-server-batch-send-response: false
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      boss-thread-size: 1

 找到 seata-1.6\bin ,执行seata-server.bat (windows) 或seata-server.sh (linux)启动

seata-server.bat  -m db  

(启动参数 

-h 主机名地址 

-p 端口(默认8090)

-m 存储模式默认file,支持db、redis等

-n 节点, 默认1

-e 环境 ,默认无)

 seata 管理控制台,用户名及密码: seata/seata

 

三、springcloud客户端服务集成

笔者使用的springcloud 及springcloud-alibaba版本如下

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

        <spring-boot.version>2.7.2</spring-boot.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>

 3.1、pom.xml中引入相应依赖包

<!-- seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>

        <!--  seata kryo 序列化-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-serializer-kryo</artifactId>
            <version>1.5.2</version>
        </dependency>

3.2 、服务的application.yml配置,新增以下配置

seata:
  enabled: true
  tx-service-group: default_tx_group
  service:
    vgroup-mapping:
      default_tx_group: default
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: localhost:8850
      namespace: seata
      group: DEFAULT_GROUP
  config:
    type: nacos #配置中心
    nacos:
      server-addr: localhost:8850
      namespace: seata
      group: DEFAULT_GROUP
      data-id: seataServer.properties

四、分布式事务(AT)案例演示

新建两个服务

yscloud-demo1 ,对应db : demo1    库中创建一个t_person表 ,服务端口:8082

yscloud-demo2 ,对应db : demo2    库中创建一个t_person_ext表,服务端口:8083

每一个服务的db中需要创建seata的undo_log表。

CREATE TABLE `undo_log` (
  `branch_id` bigint NOT NULL COMMENT 'branch transaction id',
  `xid` varchar(128) NOT NULL COMMENT 'global transaction id',
  `context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',
  `rollback_info` longblob NOT NULL COMMENT 'rollback info',
  `log_status` int NOT NULL COMMENT '0:normal status,1:defense status',
  `log_created` datetime(6) NOT NULL COMMENT 'create datetime',
  `log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='AT transaction mode undo table'
-- demo1 db
CREATE TABLE `t_person` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `sex` tinyint DEFAULT NULL,
  `phone` varchar(32) DEFAULT NULL,
  `email` varchar(128) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;


-- demo2 db
CREATE TABLE `t_person_ext` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `person_id` bigint DEFAULT NULL,
  `wx_open_id` varchar(32) DEFAULT NULL,
  `portrait` varchar(128) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

  PersonController 类


    @Autowired
    private PersonExtFeign personExtFeign;

    /**
     * SEATA AT分布式事务测试
     * @return
     */
    @GlobalTransactional
    @Transactional
    @RequestMapping(value = "/updatePerson",method = RequestMethod.GET)
    public Resp updatePerson(Long personId ,String name,String portrait){
        Person person = personMapper.selectById(personId);
        person.setName(name);
        personMapper.updateById(person);
        log.info("更新person表成功");

        log.info("调用远端feign接口");
        Resp ret = personExtFeign.updatePersonPortrait(personId, portrait);
        log.info("调用远端feign接口返回:"+ JSON.toJSONString(ret));

        int i=1/0; //模拟发生异常
        return Resp.success();
    }

 注意: 需要在起调的方法上标记 @GlobalTransactional ,开启全局事务,内部调用feign方法无需标记此注解。

 PersonExtFeign类

@FeignClient(contextId = "PersonExtFeign",
        value= "demo2-server",
        path = "/personExt"
 )
public interface PersonExtFeign {
 

 @RequestMapping(value = "/updatePersonPortrait",method = RequestMethod.GET)
 public Resp updatePersonPortrait(@RequestParam("personId") Long personId,
                                  @RequestParam("portrait") String portrait);

}

PersonExtController类


@Slf4j
@RestController
@RequestMapping(value = "/personExt")
public class PersonExtController implements PersonExtFeign {
  


    @Autowired
    private PersonExtMapper personExtMapper;
 
    @Transactional
    @RequestMapping(value = "/updatePersonPortrait",method = RequestMethod.GET)
    public Resp updatePersonPortrait(@RequestParam("personId") Long personId,
                                     @RequestParam("portrait") String portrait){

        PersonExt personExt = personExtMapper
                .selectOne(new QueryWrapper<PersonExt>().lambda().eq(PersonExt::getPersonId, personId));
        personExt.setPortrait(portrait);
        personExtMapper.updateById(personExt);
        log.info("更新personExt表成功");

        return Resp.success();
    }

}
浏览器请求;
http://localhost:8012/person/updatePerson?personId=13&name=zhangsan2&portrait=bbbb

 demo2的回滚日志(控制台) 

 undo_log日志

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

家政服务小程序实战教程08-宫格导航

小程序一般会在首页显示商品的分类&#xff0c;这类需求我们在微搭中是使用宫格导航组件来实现。 01 组件说明 宫格导航组件可以在导航配置里设置菜单&#xff0c;可以手动添加&#xff0c;也可以变量绑定 因为我们一般的分类是动态变化的&#xff0c;品类会不断的调整&#…

阿里代码规范插件中,Apache Beanutils为什么被禁止使用?

在实际的项目开发中&#xff0c;对象间赋值普遍存在&#xff0c;随着双十一、秒杀等电商过程愈加复杂&#xff0c;数据量也在不断攀升&#xff0c;效率问题&#xff0c;浮出水面。 问&#xff1a;如果是你来写对象间赋值的代码&#xff0c;你会怎么做&#xff1f; 答&#xf…

[Java 进阶面试题] CAS 和 Synchronized 优化过程

最有用的东西,是你手里的钱,有钱就有底气,还不快去挣钱~ 文章目录CAS 和 Synchronized 优化过程1. CAS1.1 CAS的原理1.2 CAS实现自增自减的原子性1.3 CAS实现自旋锁1.4 CAS针对ABA问题的优化2. synchronized2.1 synchronized加锁阶段分析2.2 synchronized优化CAS 和 Synchroniz…

nodejs+vue大学生在线选课系统vscode - Visual Studio Code

3、数据库进行设计&#xff0c;建立约束和联系。 4、创建程序框架&#xff0c;代码分成三层结构&#xff1a;接口层、业务层、表示层&#xff0c;设计窗口和主窗口&#xff0c;主窗口菜单项依照系统模块图设计。 5、设计数据访问的接口&#xff0c;供各模块调用。完成登录功能…

【JavaWeb项目】简单搭建一个前端的博客系统

博客系统项目 本项目主要分成四个页面: 博客列表页博客详情页登录页面博客编辑页 该系统公共的CSS样式 common.css /* 放置一些各个页面都会用到的公共样式 */* {margin: 0;padding: 0;box-sizing: 0; }/* 给整个页面加上背景 */ html, body{height: 100%; }body {backgrou…

printf的返回值

参考资料 点击下面的链接https://legacy.cplusplus.com/reference/cstdio/printf/?kwprintf, 返回值的理解 如果返回成功后&#xff0c;将返回写入的字符总数。 如果发生写入错误&#xff0c;则设置错误指示器&#xff08;ferror&#xff09;并返回负数。 如果在写入宽字符…

微信中如何接入chatgpt机器人才比较安全(不会收到警告或者f号)之第一步登录微信

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂。 前言 为什么会有这个话题?大家都知道最近有个AI机器人很火,那就是chatgpt,关于它的介绍,大家可以自行百度去,我这边就不多介绍了。 好多人嫌网页版玩的不过瘾,就把这个机器人接入到了QQ上,接入到了钉钉上,TG 上…

设计模式:原型模式解决对象创建成本大问题

一、问题场景 现在有一只猫tom&#xff0c;姓名为: tom, 年龄为&#xff1a;1&#xff0c;颜色为&#xff1a;白色&#xff0c;请编写程序创建和tom猫属性完全相同的10只猫。 二、传统解决方案 public class Cat {private String name;private int age;private String color;…

JMeter 接口测试/并发测试/性能测试

Jmter工具设计之初是用于做性能测试的&#xff0c;它在实现对各种接口的调用方面已经做的比较成熟&#xff0c;因此&#xff0c;本次直接使用Jmeter工具来完成对Http接口的测试。因为再做接口测试时可以设置线程组&#xff0c;所以也可做接口性能测试。本篇使用JMeter完成了一个…

TrueNas篇-trueNas Scale安装

安装TrueNAS Scale 在尝试trueNas core时发下可以成功安装&#xff0c;但是一直无法成功启动&#xff0c;而且国内对我遇见的错误几乎没有案例&#xff0c;所以舍弃掉了&#xff0c;而且trueNas core是基于Linux的&#xff0c;对Linux的生态好了很多&#xff0c;还可以可以在t…

DNS 原理入门指南(二)

三、DNS服务器 下面我们根据前面这个例子&#xff0c;一步步还原&#xff0c;本机到底怎么得到域名math.stackexchange.com的IP地址。 首先&#xff0c;本机一定要知道DNS服务器的IP地址&#xff0c;否则上不了网。通过DNS服务器&#xff0c;才能知道某个域名的IP地址到底是什么…

Qt优秀开源项目之十六:SQLite数据库管理系统—SQLiteStudio

首先&#xff0c;感谢CSDN官方认可 SQLiteStudio是一款开源、跨平台&#xff08;Windows、Linux和MacOS&#xff09;的SQLite数据库管理系统。 github地址&#xff1a;https://github.com/pawelsalawa/sqlitestudio 官网&#xff1a;https://sqlitestudio.pl/ 特性很多&#xf…

11-git-查看提交历史

查看提交历史前言查看提交历史常用选项-p-n--stat--pretty--since限制输出选项前言 本篇来学习git中查看提交历史命令 查看提交历史 官方项目例子&#xff1a; git clone https://github.com/schacon/simplegit-progit git log说明: 不传任何参数会按时间先后顺序列出所有的…

Springboot+jsp齐鲁历史文化名人网站

山东地区是齐鲁文化的发源地,也是中华文明的摇篮之一 ,早在四十万年前这里 就开始出现了人类活动的遗迹(发现于沂源骑子鞍山南麓的沂源猿人头骨化石就是最好的证据)。另外,山东省境内的新泰、长岛、日照、蓬莱等地也都发现了旧石器时代晚期的人类化石。目前,山东史前文化的发掘…

C语言fopen函数的用法

在C语言中&#xff0c;操作文件之前必须先打开文件&#xff1b;所谓“打开文件”&#xff0c;就是让程序和文件建立连接的过程。打开文件之后&#xff0c;程序可以得到文件的相关信息&#xff0c;例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中&#xff0c…

Selenium常用API详解,从入门到进阶(全套)

目录 1、打开页面 2、查找页面元素 3、输入文本 4、点击操作 5、提交操作 6、清除文本 7、获取文本、属性 8、获取页面的标题和URL 9、窗口 9.1、设置窗口大小 9.2、窗口切换 9.2.1、为什么需要窗口切换&#xff1f; 9.2.2、获取句柄的方式 9.2.3、切换句柄 10、…

秒杀项目之商品展示及商品秒杀

目录 登录方式调整 生成秒杀订单 绑定秒杀商品 查看秒杀商品 订单秒杀 移除seata相关 生成秒杀订单 前端页面秒杀测试 登录方式调整 第1步&#xff1a;从zmall-common的pom.xml中移除spring-session-data-redis依赖 注意&#xff1a; 1&#xff09;本章节中不采用spri…

Python获取搜索引擎结果

前言 想快速获取各个高校的博士招生网站&#xff0c;于是通过python先获取出有可能包含高校博士招生网站的URL&#xff0c;然后通过人为筛选得到了想要的招生网站&#xff08;注意&#xff0c;并非直接爬取&#xff0c;是间接获取的&#xff09;。 整理了一份网站名单&#x…

ModSecurity网站防火墙安装教程加WEB防御规则设置

ModSecurity安装教程加核心防御规则 资源宝分享&#xff1a;www.httple.net ModSecurity简介 ModSecurity-官网: ​​http://www.modsecurity.cn​​ ModSecurity是目前世界上使用最多的开源WAF产品&#xff0c;可谓是WAF界的鼻祖&#xff0c;跨平台的Web应用防火墙&#xff08…

学习open62541 --- [75] 生成namespace文件的简便方法

在之前的文章中&#xff0c;生成namespace文件是使用open62541提供的nodeset_compiler.py&#xff0c;根据nodeset_compiler.rst&#xff08;位于open62541/doc/&#xff09;里的描述&#xff0c;有更好的方法&#xff1a;使用cmake命令ua_generate_nodeset_and_datatypes来生成…