Seata搭建

1.初识Seata

Quick Start | Apache Seata 官网

2.准备nacos和 seata

启动nacos

startup.cmd -m standalone

账号nacos 密码nacos

搭建seata TC

这里下载的 1.4.2 

seata-server-1.4.2

1.修改seata配置文件 

registry.conf

这里我们使用nacos作为注册中心 和 配置中心

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  # 注册中心 nacos
  type = "nacos"

# 注册中心的配置
  nacos {
    application = "seata-tc-server"
    serverAddr = "127.0.0.1:8848"
    group = "DEFAULT_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }

}

# 配置文件
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos" #还是放nacos上面

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
 
}

store.mode=db
#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://192.168.181.202:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
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


#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.rollbackFailedUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000

# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none

# 关闭metrics功能,提高性能
#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

 

2.创建数据库 创建表 

建表SQL

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

3.运行 

cmd 运行 

seata-server.bat

win bat

mac sh

 什么参数不加就是默认配置 默认端口 默认信息

 nacos 注册完成

3.微服务集成Seata

比如在 pro 商品服务导入依赖

1.导入依赖 

这时老版本 2.9.9 realease springboot版本 使用的 版本

        <!--分布式事务-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <!--版本较低 1.3.0 因此排除-->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--seata starter 采用 1.4.2版本-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.4.2</version>
        </dependency>

因为自动装配,所以只需告诉服务 TC 服务的地址 在哪里

参考官网

2.yml配置

seata:
  registry: #TC服务注册中心的配置,微服务根据这些信息取注册中心获取tc服务地址
    #参考tc服务自己的 registry.conf 中的配置,
    #包括:地址 namespace, group,application-name, cluster
    type: nacos
    nacos: #TC
      server-addr: 127.0.0.1:8848
      group: DEFAULT_GROUP
      namespace: "" #因为都在public 所以用空串
      application: seata-tc-server
      username: "nacos"
      password: "nacos"
  tx-service-group: seata-demo #事务组,根据这个获取tc服务的cluster名称 自己取的名称
  #把事务做分组 订单服务商品服务 它们是一个事务 想被同一个集群管理,它们就可以设置为同一个事务组
  #方便将来做快速失败 集群容错的 管理
  service:
    vgroup-mapping: #事务组与TC服务cluster的映射关系 事务组怎么找到我的集群名称呢,那么将映射到default这个集群当中
      seata-demo: default #没有集群默认是 default nacos里   seata-demo 映射 到 default

重启

把需要做分布式事务的服务都做一遍配置

重启 

4.实现分布式事务

1.XA模式

 基于数据库实现的 Mysql支持 XA  先让一个不提交 等所有都没有问题 然后同时提交 

 失败一个回滚所有,它是基于数据库本身的实现,来阻塞提交,性能不好

 1.Seata的实现

 优势

强一致性

缺点

可用性降低了

2.代码实现

在每个需要全局事务管理的服务加上

seata:
  registry: #TC服务注册中心的配置,微服务根据这些信息取注册中心获取tc服务地址
    #参考tc服务自己的 registry.conf 中的配置,
    #包括:地址 namespace, group,application-name, cluster
    type: nacos
    nacos: #TC
      server-addr: 127.0.0.1:8848
      group: DEFAULT_GROUP
      namespace: "" #因为都在public 所以用空串
      application: seata-tc-server
      username: "nacos"
      password: "nacos"
  tx-service-group: seata-demo #事务组,根据这个获取tc服务的cluster名称 自己取的名称
  #把事务做分组 订单服务商品服务 它们是一个事务 想被同一个集群管理,它们就可以设置为同一个事务组
  #方便将来做快速失败 集群容错的 管理
  service:
    vgroup-mapping: #事务组与TC服务cluster的映射关系 事务组怎么找到我的集群名称呢,那么将映射到default这个集群当中
      seata-demo: default #没有集群默认是 default nacos里   seata-demo 映射 到 default
  data-source-proxy-mode: XA #开启数据源代理的XA模式

 加上GlobalTransaction注解

  @GetMapping("/add")
    @GlobalTransactional(rollbackFor = Exception.class)
    public R addDingdan(@RequestParam("order") String order) {
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        spuInfoEntity.setSpuName(order);
        spuInfoService.save(spuInfoEntity);

        CouponHistoryEntity couponHistoryEntity = new CouponHistoryEntity();
        couponHistoryEntity.setMemberNickName(order);
        couponFeignService.saveTrySeata(couponHistoryEntity);


        return R.ok();
    }

另一个服务 也一定要加事务要不然会造成死锁

 @RequestMapping("/save")
    @Transactional(rollbackFor = Exception.class)
    public R save(@RequestBody CouponHistoryEntity couponHistory) throws Exception {
		couponHistoryService.save(couponHistory);

       CouponHistoryEntity couponHistory1 = new CouponHistoryEntity();
        BeanUtils.copyProperties(couponHistory,couponHistory1);
        couponHistory1.setId(1011L);
        couponHistoryService.save(couponHistory1);

        CouponHistoryEntity couponHistory2 = new CouponHistoryEntity();
        BeanUtils.copyProperties(couponHistory,couponHistory2);
        couponHistory2.setId(1012L);
		couponHistoryService.save(couponHistory2);

        CouponHistoryEntity couponHistory3 = new CouponHistoryEntity();
        BeanUtils.copyProperties(couponHistory,couponHistory3);
        couponHistory3.setId(1013L);
        couponHistoryService.save(couponHistory3);

        return R.ok();
    }

2.AT模式

1.AT模式原理

 2.AT模式的脏写问题

全局锁的机制

 

3. 代码实现

上面一开始就导入了 lock_table  到 seata服务器所在的数据库

然后只需要导入 undo_log 表就可以了 每个用到分布式事务的微服务所在的数据库都必须要导入一张undo_log表

CREATE TABLE IF NOT EXISTS `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(11)      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 AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);
seata:
  data-source-proxy-mode: AT 

重启一下就完事了,无代码侵入

测试回滚成功,和上面XA一样的代码不用动

3.TCC模式

1.TCC模式原理

 

 

2.TCC代码实现

 

 1.先建一张 冻结表
 CREATE table `pms_spu_info_tbl`( 
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) Default null comment '用户ID',
  `freeze_money` int unsigned default '0' comment '冻结金额',
  `state` int default null comment '事务状态,0:try,1:confirm,2:cancel',
  Primary key (`xid`) USING BTREE
) ENGINE = InnoDB Default charset=utf8;
2.try业务

记录冻结金额和事务状态到 pms_spu_info_tbl

添加金额

3.confirm业务

根据xid 删除account_freeze表的冻结记录

4.cancel业务

减少金额 

根据xid 修改account_freeze回滚状态

state 2

5.如何判断是否空回滚
6.如何避免业务悬挂

3.声明TCC接口

 

package com.jmj.gulimall.product.tcc;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name="induct",commitMethod = "commit",rollbackMethod = "rollback")
    void induct(@BusinessActionContextParameter(paramName = "params") String params,
                @BusinessActionContextParameter(paramName = "money") int money);

    boolean commit(BusinessActionContext businessActionContext);

    boolean rollback(BusinessActionContext businessActionContext);

}
package com.jmj.gulimall.product.tcc;

import com.jmj.gulimall.product.dao.PmsSpuInfoTblMapper;
import com.jmj.gulimall.product.entity.SpuInfoEntity;
import com.jmj.gulimall.product.service.SpuInfoService;
import com.jmj.gulimall.product.vo.spu.PmsSpuInfoTbl;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private SpuInfoService spuInfoService;

    @Autowired
    private PmsSpuInfoTblMapper pmsSpuInfoTblMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void induct(String params, int money) {
        //0.获取全局事务ID
        String xid = RootContext.getXID();
        PmsSpuInfoTbl pmsSpuInfoTbl = pmsSpuInfoTblMapper.selectById(xid);
        if (pmsSpuInfoTbl != null) {
            return ;
        }


        //1.扣减可用余额
        SpuInfoEntity byId = spuInfoService.getById(9L);
        byId.setPublishStatus(byId.getPublishStatus() + money);
        spuInfoService.updateById(byId);

        //2.记录冻结金额 事务状态

        PmsSpuInfoTbl p = new PmsSpuInfoTbl();
        p.setUserId("123");
        p.setFreezeMoney(money);
        p.setState(0);
        p.setXid(xid);
        pmsSpuInfoTblMapper.insert(p);

    }

    @Override
    public boolean commit(BusinessActionContext businessActionContext) {
        //0.获取全局事务ID
        String xid = businessActionContext.getXid();

        //1.删除冻结金额
        return pmsSpuInfoTblMapper.deleteById(xid) == 1;
    }

    @Override
    public boolean rollback(BusinessActionContext businessActionContext) {
        //0.获取全局事务ID
        String xid = businessActionContext.getXid();
        PmsSpuInfoTbl pmsSpuInfoTbl = pmsSpuInfoTblMapper.selectById(xid);
        if (pmsSpuInfoTbl != null) {
            if (pmsSpuInfoTbl.getState() ==2) {
                //幂等操作
                return true;
            }

            Integer freezeMoney = pmsSpuInfoTbl.getFreezeMoney();
            //1.扣减可用余额
            SpuInfoEntity byId = spuInfoService.getById(9L);
            byId.setPublishStatus(byId.getPublishStatus() - freezeMoney);
            spuInfoService.updateById(byId);

            pmsSpuInfoTbl.setState(2);
            pmsSpuInfoTblMapper.updateById(pmsSpuInfoTbl);
        }else {
            PmsSpuInfoTbl pmsSpuInfoTbl1 = new PmsSpuInfoTbl();
            String params = businessActionContext.getActionContext("params").toString();
            pmsSpuInfoTbl1.setUserId(params);
            pmsSpuInfoTbl1.setState(2);
            pmsSpuInfoTbl1.setFreezeMoney(0);
            pmsSpuInfoTbl1.setXid(xid);
            pmsSpuInfoTblMapper.insert(pmsSpuInfoTbl1);
        }
        return true;
    }
}
 @GetMapping("/testTcc")
    public R testTcc() {
        accountTCCService.induct("JMJ",12);
        return R.ok();
    }
package com.jmj.gulimall.coupon.controller;


import com.jmj.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;


@FeignClient(value = "gulimall-product",path = "/product/spuinfo")
public interface PmsFeignService {

    @GetMapping("/testTcc")
    public R testTcc();
}
  @GetMapping("/tet/tcc")
    @GlobalTransactional(rollbackFor = Exception.class)
    public R tcc(){
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponImg(UUID.randomUUID().toString());
        couponEntity.setCouponName(UUID.randomUUID().toString());
        couponService.save(couponEntity);

        pmsFeignService.testTcc();


        if (true){
            throw new RuntimeException("测试异常");
        }
        return R.ok();
    }

最终回滚

 能和AT模式混用

4.SAGA模式

类似于工作流 

 无隔离性

 5.SEATA高可用

1.实现微服务高可用和异地容灾

 本地模拟复制一份 文件夹 

把配置文件改成杭州集群

启动命令

seata-server.bat -p 8092

这样集群部署成功了

 若出现容灾的情况下

利用nacos的配置热更新 就可以了

可以新建一个通用客户端配置

client.yaml

官网有详细配置

这里用我自己的简略版

#事务组的映射关系
service.vgroupMapping.seata-demo=default

service.enableDegrade=false
service.disableGlobalTransaction=false

#与TC服务的通信配置

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

#rm配置
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
#tm配置
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
#undo配置
client.undo.dataValidation=true
client.undo.logSerialization=jackson
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

自动刷新 注解这里记录一下


/**
 * 优惠券信息
 *
 * @author jiangmingji
 * @email 123456789@qq.com
 * @date 2024-03-21 21:24:36
 */
@RefreshScope //动态从配置中心获取配置
@RestController
@RequestMapping("/coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;


    @Value("${coupon.user.name}")
    private String name;
    @Value("${coupon.user.age}")
    private Integer age;

微服务读取配置

 这样给微服务 配上配置就可以了

seata:
  data-source-proxy-mode: AT #开启数据源代理的XA模式
  registry: #TC服务注册中心的配置,微服务根据这些信息取注册中心获取tc服务地址
    #参考tc服务自己的 registry.conf 中的配置,
    #包括:地址 namespace, group,application-name, cluster
    type: nacos
    nacos: #TC
      server-addr: 127.0.0.1:8848
      group: DEFAULT_GROUP
      namespace: "" #因为都在public 所以用空串
      application: seata-tc-server
      username: "nacos"
      password: "nacos"
  tx-service-group: seata-demo #事务组,根据这个获取tc服务的cluster名称 自己取的名称
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group: 'SEATA_GROUP'
      dataId: 'client.properties'
      username: 'nacos'
      password: 'nacos'
      namespace: ""

重启服务 

修改配置

将集群切换为杭州 HZ 

 

成功注册到8092那个seata-server上面了 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

selenium+pyqt5自动化工具总结

说明&#xff1a;本工具是&#xff0c;操作外部google浏览器、selenium是无法操作qt界面中嵌套的浏览器的&#xff0c; 工具在后面 1. 代码结构 pycharm打开的文件下&#xff0c;再写一个子文件&#xff0c;文件导入的时候把子文件名带上 这样就可以在 外层使用命令 pyinst…

.NET 终止或结束进程

如何使用 C# 终止进程。 使用简单的方法终止.NET中的现有进程Process.Kill()。有一个可选参数 true 或 false&#xff0c;用于结束与要结束的进程相关的所有子进程。 了解如何创建流程。 结束当前进程&#xff1a; System.Diagnostics.Process.GetCurrentProcess().Kill(tru…

怎么实现Redis的高可用?

大家好&#xff0c;我是锋哥。今天分享关于【怎么实现Redis的高可用&#xff1f;】面试题。希望对大家有帮助&#xff1b; 怎么实现Redis的高可用&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 为了实现 Redis 的高可用性&#xff0c;我们需要保证在发…

大数据技术实训:Hadoop完全分布式运行模式配置

准备&#xff1a; 1&#xff09;准备3台客户机&#xff08;关闭防火墙、静态ip、主机名称&#xff09; 2&#xff09;安装JDK 3&#xff09;配置环境变量 4&#xff09;安装Hadoop 5&#xff09;配置环境变量 6&#xff09;配置集群 7&#xff09;单点启动 8&#xff09;配置ss…

【Uniapp-Vue3】Prop校验与prop默认值用法及循环遍历数组对象

一、prop校验 如果我们在想要限制prop的类型&#xff0c;就可以在接收prop的时候对接收类型进行限制&#xff1a; defineProps({ 属性名:{ type:类型 } }) 需要注意类型的首字母大写 但是设置了传入参数类型限制并不能严格限制&#xff0c;只会在后台进行提示&#xff1a; 二、…

开启Excel导航仪,跨表跳转不迷路-Excel易用宝

都2025年了&#xff0c;汽车都有导航了&#xff0c;你的表格还没有导航仪吗&#xff1f;那也太OUT了。 面对着一个工作簿中有N多个工作表&#xff0c;工作表中又有超级表&#xff0c;数据透视表&#xff0c;图表等元素&#xff0c;如何快速的切换跳转到需要查看的数据呢&#…

【Unity3D日常开发】Unity3D中适用WEBGL打开Window文件对话框打开/上传文件

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 Unity3D发布的WEBGL程序是不支持直接的I/O操…

《安富莱嵌入式周报》第348期:开源低功耗测试仪,开源创意万用表,续航100-300小时,开源PCB电机,自制shell和网络协议栈,开源水培自动化系统

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1Tzr9Y3EQ7/ 《安富莱嵌入式周报》第348期&#xff1a;开源低功…

音频合成的常见问题

使用了1年多的音频合成&#xff0c;有些常见的问题分享给大家 。 一、音质问题 噪声 背景噪声&#xff1a;在音频合成过程中&#xff0c;可能会引入背景噪声。这可能是由于原始音频素材本身质量不佳&#xff0c;比如录制环境嘈杂&#xff0c;包含电脑风扇声、外界交通声等。当…

用AI技术提升Flutter开发效率:ScriptEcho的力量

引言 在当今快速发展的技术时代&#xff0c;Flutter作为一种跨平台开发框架&#xff0c;正在越来越多的开发者中崭露头角。它不仅能够为开发者提供一套代码同时部署到iOS和Android平台的解决方案&#xff0c;还能帮助企业节省人力成本和开发时间。然而&#xff0c;对于新手开发…

SmartAIChain荣获重要认可

2024年12月21日,洛杉矶尔湾市——在今年尔湾举办的交流会上,黄荣先生的SmartAIChain项目获得了重要认可。此次活动汇聚了来自各地的杰出人才以及社区代表,共同庆祝这一创新性艺术的时刻。 在活动中,核桃市议员伍立伦(Allen Wu)的代表黄冬平女士发言,并为黄荣先生颁发了荣誉证书…

EFT信号测试和电源测试经验笔记

1. 什么是EFT 标准&#xff1a;perlEC 61000-4-4 eft设备将群脉冲干扰加到信号或者电源上&#xff0c;常见的频率是 5K 100K 两个频率 电压 电源3k&#xff0c;信号2k -----电网设备 电源4K -------------------空调设备 大概就是下图这样的周期性脉冲 1.1 电源eft 通过信…

web前端学习总结(一)

web前端使用三项技术:html、css、javascript. 一、html:超文本标记语言&#xff0c;用于展示网页的框架。 <html> <head><title> </title></head><body><div> </div> <!--用于布局&#xff0c;占1行 --><span&g…

【web靶场】之upload-labs专项训练(基于BUUCTF平台)

前言 该靶场&#xff0c;是通过平台BUUCTF在线评测中的靶场进行的&#xff0c;基于linux搭建的 当然若是想要该靶场&#xff0c;可以采用github上的醒目&#xff0c;点击后面文字即可访问c0ny1/upload-labs: 一个想帮你总结所有类型的上传漏洞的靶场 或者本人分享在网盘中&a…

ES 的倒排索引

目录 什么是 elasticSearch。 什么是倒排索引 Term Index 是什么 Stored Fields 是什么 Doc Values 是什么 segment lucene 是什么 高性能 高扩展性 高可用 Node 角色分化 去中心化 ES 是什么? ES 和 Kafka 的架构差异 ES 的写入流程 ES 的搜索流程 查询阶段…

微服务电商平台课程六:后端代码框架认识

本地环境搭建好,大家可以进行调试,并能够修改其中代码。 后端技术栈 Spring Boot是伴随着Spring4.0共同诞生的,它的目的就是简化spring的配置及开发,并协助开发人员可以整体管理应用程序的配置而不再像以前那样需要做大量的配置工作,它提供了很多开发组件,并且内嵌了we…

Unity教程(二十)战斗系统 角色反击

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

Garnet:微软官方基于.Net 8开源缓存系统,可无需任何改动直接替代Redis,而且还更高性能!

近日微软官方开源了一个开源缓存系统&#xff0c;可完全替代Redis。 01 项目简介 Garnet是微软官方基于.Net 8开发的、开源高性能远程缓存存储系统&#xff0c;支持单节点、集群。 Garnet使用的是当前流行的 RESP 协议&#xff0c;使得当前大多数编程语言现成的 Redis 客户端…

java项目之网上点餐系统源码(springboot+mysql+vue)

大家好我是风歌&#xff0c;曾担任某大厂java架构师&#xff0c;如今专注java毕设领域。今天要和大家聊的是一款基于springboot的网上点餐系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 网上点餐系统的主要使用者分为管理员登录…

深入Android架构(从线程到AIDL)_23 活用IBinder接口于近程通信01

1、 在同一进程里活用IBinder接口 议题 1. myActivity对象是谁创建的呢? 2. myService对象是谁创建的呢? 3. 当myService类里有个f1()函数&#xff0c;如何去调用它呢? 4. 必须先取得myService对象的指针&#xff0c;才能调用f1()函数去存取对象的属性(Attribute)值。 …