springCloudeAlibaba的使用

父pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <modules>
        <module>order</module>
        <module>common</module>
        <module>user</module>
<!--        <module>stock1</module>-->
        <module>openFeignOrder</module>
    </modules>


    <groupId>org.example</groupId>
    <artifactId>springCloudAlibaba</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
    </dependencies>

    <!--dependencyManagement 是不会被子模块直接继承的,需要引入,但是不需要版本号-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <!--    导入spring-cloud-alibaba-->
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <!--    导入spring-cloud-->
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR8</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <skywalking.version>8.5.0</skywalking.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

(一定要遵从springcloude版本约定的各个组件版本号,直接往上搜来看版本发布说明 | Spring Cloud Alibaba (aliyun.com))首先原来的服务注册与发现eureka被替代为nacos,直接下载运行 startup.cmd ,要改成单机运行:

set MODE="standalone"

然后配置文件这样配置yml:

server:
  port: 8001
spring:
  application:
#注册成功后,这就是你的服务名
    name: user-server
  cloud:
    nacos:
      #      nacos服务ip
      server-addr: 192.168.126.1:8848
      discovery:
        #        空间id
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        #        分组
        group: TEST

 调用方式:

package com.stockServer.controller;

import com.common.util.MyServerNameUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @program: springCloudAlibaba
 * @author: quxiao
 * @create: 2024-02-03 12:57
 **/
@RequestMapping("/dingDan")
@RestController
public class DingDanController {
    @Autowired
    RestTemplate restTemplate;


    @PostMapping("/xiadan")
    public String xiadan() {
        String template = restTemplate.postForObject("http://" + "user-server" + "/XiaDab/jianKuChun", null, String.class);
        return template;
    }
}

就不再需要指定完全的url地址,还有就是默认集成了ribbon调用方式,也就是说,可以自己设定调用的方式,轮询、随机。。。。

package com.stockServer.config;

import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @program: springCloudAlibaba
 * @author: quxiao
 * @create: 2024-02-03 13:00
 **/
@Configuration
public class SpringConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

    @Bean
    public IRule getRule() {
//        随机掉用
        return new RandomRule();
    }
}

使用open-fegin进行调用,不再需要使用url的方式,直接声明接口(请直接创建一个新的模块,不要再图方便,直接修改能跑的模块了!!!!!!!!!):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springCloudAlibaba</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openFeignOrder</artifactId>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>
package com.stockServer.fegin;

import com.common.dto.MsgData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
//指定远程接口的服务名,path是@RequestMapping的地址
@FeignClient(name = "user-server", path = "XiaDab")
public interface openFeginOrder {
    @PostMapping("/jianKuChun")
    public String jianKuChun();

    @PostMapping("/quxiao")
//方法名可以不同,但是 @PostMapping("/quxiao")必须完全一样!
    public MsgData quxiao();
}

调用方式:

package com.stockServer.controller;

import com.stockServer.fegin.openFeginOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: springCloudAlibaba
 * @author: quxiao
 * @create: 2024-02-03 12:57
 **/
@RequestMapping("/dingDan")
@RestController
public class DingDanController {
//直接注入这个接口,调用它的方法
    @Autowired
    openFeginOrder openFeginOrder;


    @PostMapping("/xiadan")
    public String xiadan() {
        String template = openFeginOrder.quxiao1().toString();
        return template;
    }

}

记得开启fegin哦(我在项目上就是因为没开启,导致一直走降级方法。。。。)

开启:

package com.stockServer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
//开启fegin调用
@EnableFeignClients
public class fenginOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(fenginOrderApplication.class);
    }
}

也就是说,相当于再我这个服务写一个调用另一个服务的controller,标记了url地址。

(另一种方式是直接在每一个服务上写一个api模块,每一个服务都有)

然后实现对外的接口,具体逻辑写好,另一个模块引入然后调用。

还有另一种远程调用的方式:

 专门用一个api模块来表示是这个服务对外接口。

具体实现由server来实现。

 启动类将对外的接口加载进来

Sentinel限流,容灾等使用:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
 private static final String T1 = "t1";

    //注解方式
    //blockHandlerClass 将限流的方法写在指定的类中,静态,公共的
    //blockHandler 指定达到限流后执行的方法
    //fallback 发生异常后,容灾方法
    //fallbackClass 将容灾的方法写在指定的类中,静态,公共的
    @GetMapping("/t1")
    @SentinelResource(value = T1, blockHandlerClass = test.class, blockHandler = "t1cw", fallback = "t1rz", fallbackClass = test.class)
    public String t1() {
        //代码的方式添加限流,或者容灾
//        Entry entry = null;
//        try {
//            entry = SphU.entry("t1");
//        } catch (BlockException e) {
//            return "被限流了";
//        } catch (Exception e) {
//            Tracer.traceEntry(e, entry);
//        } finally {
//            if (entry != null) {
//                entry.exit();
//            }
//        }
//        int a = 0 / 1;
//        a = 1 / 0;
        return "t1";
    }

    @PostConstruct
    private static void init() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //接口名
        rule.setResource("t1");
        //限流策略
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

Sentinel有一个网页界面,拿来查看具体数据:

需要去官网相爱一个jar包,然后运行。并且在需要监听的心目中指定页面的端口

java -jar sentinel-dashboard-1.8.0.jar --server.port=8002

(dashboard: localhost:8002):

server:
  port: 8011
spring:
  application:
    name: stock1-server
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8002
    nacos:
      server-addr: 192.168.126.1:8848
      discovery:
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        group: TEST

限流、降级方法的指定方式:

1、直接在接口的同一个类里指定:参数名,返回值相同,多一个异常

BlockException类

    @GetMapping("getStock2/{id}")
    @SentinelResource(value = "getStock2", blockHandler = "getStock2err")
    public String getStock2(@PathVariable("id") long id) {
        return "" + id;
    }

    public String getStock2err(@PathVariable("id") Long id, BlockException e) {
        return "限流操作";
    }
 2、放在指定的类里面:
public class test {
    public static String t1cw(BlockException e) {
        return "流控方法";
    }

    public static String t1rz(Throwable e) {
        return "发生错误方法";
    }
    /**
     * blockHandlerClass 流控方法类
     * blockHandler 流控方法名
     * fallbackClass 降级(发生异常)方法类
     * fallback 降级(发生异常)方法名
     */
    @GetMapping("/t2")
    @SentinelResource(value = "t2", blockHandlerClass = test.class, blockHandler = "t1cw", fallback = "t1rz", fallbackClass = test.class)
    public String t2() {
        return "t2";
    }

将需要调用的方法放在其他类中,是有约定的,方法必须是static的,因为这个方法必须比接口对应的方法先加载到jvm中。

3、全局管理:
package com.stock1Server.ecception;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {

        String rs = null;

        if (e instanceof FlowException)
            rs = "接口限流了";
        else if (e instanceof DegradeException)
            rs = "服务降级了";
        else if (e instanceof ParamFlowException)
            rs = "参数限流了";
        else if (e instanceof AuthorityException)
            rs = "权限规则不通过";
        else if (e instanceof SystemBlockException)
            rs = "系统保护";

        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().write(rs);

    }
}

流控规则介绍:

直接:

达到流控要求是,直接进行流控(执行流控方法)、

关联:

意识是不在为自己设置流控,而是为他人,只要他人达到流控约束条件,我就执行流控方法。

链路模式不做介绍,用的太少了。

流控效果

快速失败就是达到流控时,直接调用流控方法
warm up

是预热模式,就是处理能力会越来越强,适合激增请求的场景。

排队等待

就是有心跳式的访问,一下子多,停一会,又一下子变多。中间有一定的等待时间,这一段时间就可以拿来让服务器处理。

 降级规则:

慢调用比例

最小5此请求,达到10%次执行时间超过1000毫秒,持续10秒开始执行降级方法,10秒后,若第一次执行时间超过1000毫米,又持续10秒开始执行降级方法(半开状态)直到新的一次调用小于1000毫秒。

异常比例:

最小5此请求,达到10%次异常,持续10秒开始执行降级方法,10秒后,若第一次执行时间超过1000毫米,又持续10秒开始执行降级方法(半开状态)直到新的一次调用小于1000毫秒。

异常数:

最小5此请求,达到1次异常,持续10秒开始执行降级方法,10秒后,若第一次执行时间超过1000毫米,又持续10秒开始执行降级方法(半开状态)直到新的一次调用小于1000毫秒。

结合openfigen

要在配置文件中开启sentinel和openfigen的使用

feign:
  sentinel:
    enabled: true

然后再提供方,调用方都加上:依赖,并且开启上面的两个框架的集成。

热点规则使用:

一句话:给方法参数的某个数据添加流控,例如:给id为1、2、3添加流控,1秒2次就开启流控。其他数据1秒5次开启流控。

用sentinel页面这玩意看运气,我添加了一下午才成功这一次,用代码添加如下:

  @PostConstruct
    public static void initParamFlowRule() {
        //使用这个方式,居然没有调用我指定的限流方法,待解决
        List<ParamFlowRule> rules = new ArrayList<>();
        ParamFlowRule rule = new ParamFlowRule();
        //阈值类型:只支持QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //其它参数调用次数
        rule.setCount(10);
        //接口名
        rule.setResource("getStock2");
        //第几个参数,0为第一个
        rule.setParamIdx(0);
        //约定时间
        rule.setDurationInSec(1);

        List<ParamFlowItem> items = new ArrayList<>();

        ParamFlowItem item1 = new ParamFlowItem();
        item1.setClassType(long.class.getName());
        //超过约定时间访问参数
        item1.setCount(2);
        //具体参数值
        item1.setObject("1");

        items.add(item1);
        rule.setParamFlowItemList(items);
        rules.add(rule);
        ParamFlowRuleManager.loadRules(rules);
    }

 持久化sentinel配置:

就是将图形化界面的配置,用json的格式,挨个挨个配置到nacos的config中,我在想,高版本的sentinel应该会出现直接保存到nacos的mysql数据库中,然后直接快熟导入。

           <!--        sentinel持久化依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--        nacos配置文件依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

一个是持久化依赖,一个是nacos配置中心的依赖,再配置中心手动加上配置:

代码项目中使用:

server:
  port: 8011
spring:
  application:
    name: stock1-server
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8002
      datasource:
        flow-rule:
          nacos:
            server-addr: 192.168.126.1:8848
            data-id: stock1-server-sentinel-config
            ruleType: flow

    nacos:
      server-addr: 192.168.126.1:8848
      discovery:
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        group: TEST
feign:
  sentinel:
    enabled: true

seata分布式事务搭建:

首先需要下载对应的steta版本,并且记得把源码版也下上,后面将配置导入nacos需要用:

修改配置:

file.con文件


## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"

  db {
    datasource = "druid"
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://192.168.126.128:3306/seata?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

}

就是指定自己的mysql数据库地址,外加三张必须得表:

源码文件的这里:

然后是配置到nacos的文件:

registry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "192.168.126.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "192.168.126.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }

  file {
    name = "file.conf"
  }
}

就是指定nacos的地址,加载到nacos后seata的基本信息。

导入配置到nacos中:

既然是使用nacos的配置,就得把配置放进nacos配置源中,在seata的源码文件中,有快速将配置加载到nacos配置源中的方法:

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
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
service.vgroupMapping.my_test_tx_group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
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=false
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=db
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
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=mysql://192.168.126.128:3306/seata?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=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.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
store.redis.host=127.0.0.1
store.redis.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.database=0
store.redis.password=null
store.redis.queryLimit=100
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
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.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

修改这几个地方:

store.mode=db

store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=mysql://192.168.126.128:3306/seata?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
store.db.user=root
store.db.password=123456

和前面的file.con文件保持一致,唯一不同的就是这个store.db.url的连接方式,我用和file.con文件一样的,它就报错,连接不上后来差了资料,改了链接语句。

然后必须有git软件在电脑上,它可以运行bash语句,也就是linux的。

有python也可以。

项目配置:

然后在需要使用seata全局事务配置文件中,加上对seata的配置:

server:
  port: 8011
spring:
  application:
    name: stock1-server
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8002
      datasource:
        flow-rule:
          nacos:
            server-addr: 192.168.126.1:8848
            data-id: stock1-server-sentinel-config
            ruleType: flow

    nacos:
      server-addr: 192.168.126.1:8848
      discovery:
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        group: TEST
    alibaba:
      seata:
        tx-service-group: my_test_tx_group #事务分组
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://192.168.126.128:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    username: root
    password: 123456
feign:
  sentinel:
    enabled: true
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 192.168.126.1:8848 #nacos地址
      application: seata-server #在nacos中的服务名
      username: nacos  #nacos账号密码
      password: nacos
      group: SEATA_GROUP #在nacos中的分组名
  config:
    nacos:
      server-addr: 192.168.126.1:8848

添加这两个地方:

seata分组是在上面config.txt中配置的:

service.vgroupMapping.my_test_tx_group=default

使用 :my_test_tx_group

使用全局事务处理:

    @GlobalTransactional
    @GetMapping("getStock1/{code}")
    @GlobalLock
    @SentinelResource(value = "getStock1", fallback = "getStock1err")
    public MsgTxt getStock1(@PathVariable("code") String code) {
        MsgTxt print = stock1FeignClient.print(code, 14);//扣除数量
        worktableService.updateByIdTest1();//保存单号
        int a = 1 / 0;//发生异常
        return print;
    }

扣除数量就是一个远程方法,扣除数据。

然后本服务发生异常,就会通知seata回滚,本方法修改了的表也会回滚,seata现在使用的是AT管理,自动事务。

当开启分布式事务时,调用sql方法,就会在seata的数据库中保留回滚的数据,如下:

global_table表就是存放执行分布式方法时,进入全局方法,就会生产它,这个方法的全局信息。

lock_table表是运行数据库操作后,生产一个表信息。操作一个表,增加一个信息。如下:

我就执行了远程服务的方法,里面操作了两个表,seata就生成了两条数据:

branch_table表存放的是涉及到了多少个服务。很明显我调用了两个服务,所以两条数据,并且保存各自的服务信息。

undo_log表就是存放执行情况,只要是修改了的数据,都会保存在这,里面包含了修改前数据,修改后数据。

修改前数据:    
"beforeImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "worktable",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "i1",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": 1
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "i2",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "123321"
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                }
修改后数据
"afterImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "worktable",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "i1",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": 1
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "i2",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "20212904"
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                }

保存的发生修改sql之前的数据,和修改之后的数据。如果发生异常,就根据这里保存的数据,执行反向sql回滚

还有另一个注解,分布式数据库锁:

@GlobalLock

一旦标识了这个,该方法在执行时,就回去获取锁,如果正好这条数据库数据还在分布式事务中,就会报错,不允许修改。读取不受限制。

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@55b12ac0] was not registered for synchronization because synchronization is not active
2024-03-09 16:18:42.997  WARN 2780 --- [nio-8011-exec-4] c.a.druid.pool.DruidAbstractDataSource   : discard long time none received connection. , jdbcUrl : jdbc:mysql://192.168.126.128:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC, version : 1.2.4, lastPacketReceivedIdleMillis : 433818
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@5b76de06] will not be managed by Spring
==>  Preparing: UPDATE user SET user_code=? WHERE (id = ?)
==> Parameters: 新数据(String), 14(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@55b12ac0]
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4aeaba]
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@3c86fa5a] will be managed by Spring
==>  Preparing: UPDATE worktable SET i2=? WHERE (i1 = ?)
==> Parameters: 多了一个表(String), 2(Integer)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4aeaba]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4aeaba]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4aeaba]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4aeaba]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3c0e5228] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@7dbe36da] will not be managed by Spring
==>  Preparing: UPDATE user SET user_code=? WHERE (id = ?)
==> Parameters: er(String), 14(Integer)
2024-03-09 16:18:46.397 ERROR 2780 --- [nio-8011-exec-5] i.s.r.d.exec.AbstractDMLBaseExecutor     : execute executeAutoCommitTrue error:Global lock wait timeout

io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout
	at io.seata.rm.datasource.exec.LockRetryController.sleep(LockRetryController.java:52) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:302) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor$LockRetryPolicy.execute(AbstractDMLBaseExecutor.java:155) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.executeAutoCommitTrue(AbstractDMLBaseExecutor.java:110) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.doExecute(AbstractDMLBaseExecutor.java:74) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.BaseTransactionalExecutor.execute(BaseTransactionalExecutor.java:115) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:113) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:51) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.PreparedStatementProxy.execute(PreparedStatementProxy.java:55) [seata-all-1.3.0.jar:1.3.0]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59) [mybatis-3.5.7.jar:3.5.7]
	at com.sun.proxy.$Proxy123.execute(Unknown Source) [na:na]
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47) [mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) [mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) [mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) [mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) [mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194) [mybatis-3.5.7.jar:3.5.7]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) [mybatis-spring-2.0.6.jar:2.0.6]
	at com.sun.proxy.$Proxy82.update(Unknown Source) [na:na]
	at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:288) [mybatis-spring-2.0.6.jar:2.0.6]
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:64) [mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) [mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) [mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.sun.proxy.$Proxy83.update(Unknown Source) [na:na]
	at com.baomidou.mybatisplus.extension.service.IService.update(IService.java:167) [mybatis-plus-extension-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.extension.service.IService.update(IService.java:157) [mybatis-plus-extension-3.4.3.jar:3.4.3]
	at com.stock1Server.service.impl.UserServiceImpl.updateTest(UserServiceImpl.java:24) [classes/:na]
	at com.stock1Server.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$3e673818.invoke(<generated>) [classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) [spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at com.stock1Server.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$c2539cd9.updateTest(<generated>) [classes/:na]
	at com.stock1Server.controller.stockController.t6(stockController.java:118) [classes/:na]
	at com.stock1Server.controller.stockController$$FastClassBySpringCGLIB$$ae77ee83.invoke(<generated>) [classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) [spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.lambda$handleGlobalLock$0(GlobalTransactionalInterceptor.java:134) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.GlobalLockTemplate.execute(GlobalLockTemplate.java:48) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalLock(GlobalTransactionalInterceptor.java:132) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:124) [seata-all-1.3.0.jar:1.3.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) [spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at com.stock1Server.controller.stockController$$EnhancerBySpringCGLIB$$e2df0638.t6(<generated>) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.46.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.46.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_171]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_171]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_171]
Caused by: io.seata.rm.datasource.exec.LockConflictException: null
	at io.seata.rm.datasource.ConnectionProxy.checkLock(ConnectionProxy.java:119) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.processLocalCommitWithGlobalLocks(ConnectionProxy.java:205) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.doCommit(ConnectionProxy.java:198) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.lambda$commit$0(ConnectionProxy.java:184) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.execute(ConnectionProxy.java:289) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.commit(ConnectionProxy.java:183) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.lambda$executeAutoCommitTrue$0(AbstractDMLBaseExecutor.java:112) [seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:299) ~[seata-all-1.3.0.jar:1.3.0]
	... 104 common frames omitted

Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3c0e5228]
2024-03-09 16:18:46.466 ERROR 2780 --- [nio-8011-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.QueryTimeoutException: 
### Error updating database.  Cause: io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout
### The error may exist in com/stock1Server/mapper/UserMapper.java (best guess)
### The error may involve com.stock1Server.mapper.UserMapper.update-Inline
### The error occurred while setting parameters
### SQL: UPDATE user  SET user_code=?      WHERE (id = ?)
### Cause: io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout
; Global lock wait timeout; nested exception is io.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeout] with root cause

io.seata.rm.datasource.exec.LockConflictException: null
	at io.seata.rm.datasource.ConnectionProxy.checkLock(ConnectionProxy.java:119) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.processLocalCommitWithGlobalLocks(ConnectionProxy.java:205) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.doCommit(ConnectionProxy.java:198) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.lambda$commit$0(ConnectionProxy.java:184) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.execute(ConnectionProxy.java:289) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy.commit(ConnectionProxy.java:183) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.lambda$executeAutoCommitTrue$0(AbstractDMLBaseExecutor.java:112) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:299) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor$LockRetryPolicy.execute(AbstractDMLBaseExecutor.java:155) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.executeAutoCommitTrue(AbstractDMLBaseExecutor.java:110) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.AbstractDMLBaseExecutor.doExecute(AbstractDMLBaseExecutor.java:74) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.BaseTransactionalExecutor.execute(BaseTransactionalExecutor.java:115) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:113) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:51) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.datasource.PreparedStatementProxy.execute(PreparedStatementProxy.java:55) ~[seata-all-1.3.0.jar:1.3.0]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59) ~[mybatis-3.5.7.jar:3.5.7]
	at com.sun.proxy.$Proxy123.execute(Unknown Source) ~[na:na]
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194) ~[mybatis-3.5.7.jar:3.5.7]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.6.jar:2.0.6]
	at com.sun.proxy.$Proxy82.update(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:288) ~[mybatis-spring-2.0.6.jar:2.0.6]
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:64) ~[mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) ~[mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.4.3.jar:3.4.3]
	at com.sun.proxy.$Proxy83.update(Unknown Source) ~[na:na]
	at com.baomidou.mybatisplus.extension.service.IService.update(IService.java:167) ~[mybatis-plus-extension-3.4.3.jar:3.4.3]
	at com.baomidou.mybatisplus.extension.service.IService.update(IService.java:157) ~[mybatis-plus-extension-3.4.3.jar:3.4.3]
	at com.stock1Server.service.impl.UserServiceImpl.updateTest(UserServiceImpl.java:24) ~[classes/:na]
	at com.stock1Server.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$3e673818.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at com.stock1Server.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$c2539cd9.updateTest(<generated>) ~[classes/:na]
	at com.stock1Server.controller.stockController.t6(stockController.java:118) ~[classes/:na]
	at com.stock1Server.controller.stockController$$FastClassBySpringCGLIB$$ae77ee83.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.lambda$handleGlobalLock$0(GlobalTransactionalInterceptor.java:134) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.rm.GlobalLockTemplate.execute(GlobalLockTemplate.java:48) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalLock(GlobalTransactionalInterceptor.java:132) ~[seata-all-1.3.0.jar:1.3.0]
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:124) ~[seata-all-1.3.0.jar:1.3.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at com.stock1Server.controller.stockController$$EnhancerBySpringCGLIB$$e2df0638.t6(<generated>) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.46.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.46.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.46.jar:9.0.46]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]

gateway路由网关:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

gateway是springcloud发出的,由于Netflix组件没有继续维护了,所以spring官方就开发了一个网关路由。

使用起来也是很简单,直接在配置文件中配置:

server:
  port: 8080
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: oder_route
          uri: lb://order1-server
          predicates:
            - Path=/oder/**
          filters:
            - StripPrefix=1
    nacos:
      server-addr: 192.168.126.1:8848
      discovery:
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        group: TEST

Path=/oder/**是将路径前面加一个前缀,用于区分服务之间的路径。

StripPrefix=1是切割掉上面的前缀

lb://order1-server是指定这个配置代理的服务。

也可以直接开启自动代理,直接用服务名取调用:

server:
  port: 8080
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
    nacos:
      server-addr: 192.168.126.1:8848
      discovery:
        namespace: c1102e00-c947-4d0c-8320-b98dc7fae641
        group: TEST

localhost:8080/order1-server/order1/getOder2/10010

order1-server就是服务名。

gateway全局过滤器

package com.gateway.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @program: springCloudAlibaba
 * @author: quxiao
 * @create: 2024-03-11 21:04
 **/
@Component
@Slf4j
public class GatewayFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //输出访问路径
        log.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

集合sentinen:

        <!-- Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

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

另一个要注意的是,这个可以根据api分组来限流熔断:

只定义返回消息:

package com.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;

import javax.annotation.PostConstruct;

@Configuration
public class SentinelConfiguration {

    @PostConstruct
    private void initBlockHandler() {
        BlockRequestHandler blockRequestHandler = (exchange, t) ->
                ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue("限流了")
                        );
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

}

skywalking链路追踪

ksysalking可以查看服务中的调用路径,可以清楚看清服务之间的依赖。

需要下载ksysalking的服务启动包:

链接: https://pan.baidu.com/s/1-icaoGf_CLY2PYF2D6lbEg

提取码: xrix 复制这段内容后打开百度网盘手机App,操作更方便哦

然后修改配置文件:

修改一个端口:

然后启动服务:

然后在配置文件中配置依赖:

        <!-- 该引用用于logback获取tranceId,也就是tid -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>${skywalking.version}</version>
        </dependency>

        <!-- 该引用用于代码获取tranceId -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>${skywalking.version}</version>
        </dependency>

连接skywalking

在运行之前,加上VM配置:

-javaagent:D:\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar
-DSW_AGENT_NAME=gateway-server
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

是skywalking服务文件中的探针服务:

-javaagent:D:\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar

服务名称
-DSW_AGENT_NAME=gateway-server

ksysalking的服务端口号
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

然后再代码中指定接口链路:

    @Trace
    @Tags(value = {
            @Tag(key = "print", value = "returnedObj")
            , @Tag(key = "print", value = "arg[0]")
    })
    public MsgTxt print(String txt, int id) {
        boolean b = userService.updateTest(txt, id);
        return new MsgTxt(txt, b);
    }

    @Trace

标识查看调用这个方法的链路

    @Tags(value = {
            @Tag(key = "print", value = "returnedObj")
            , @Tag(key = "print", value = "arg[0]")
    })

print是方法名

returnedObj标识在skywalking查看是显示方法的返回值:

arg[0]标识第一个参数

性能剖析

点击接口的调用,然后分析,能看见哪一句代码耗时最长:

集成logback日志:

上面已经导入了jar包,之后需要配置logback-spring.xml日志输出格式:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 日志输出格式 -->
    <property name="FILE_LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] %green(%-5level) [%thread] %yellow([%tid]) %cyan(%logger{50}) : %msg%n" />

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 默认日志打印的格式 -->
        <!--<encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>-->
        <!-- 配置了skywalking的traceId的日志打印的格式 -->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>${FILE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>
    <!-- 异步输出 控制台 -->
    <appender name="ASYNC_STDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>256</queueSize>
        <appender-ref ref="STDOUT"/>
    </appender>

    <!-- 使用gRpc将日志发送到skywalking服务端 -->
    <appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>${FILE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="ASYNC_STDOUT"/>
        <appender-ref ref="GRPC_LOG"/>
    </root>

    <root level="info">
        <appender-ref ref="ASYNC_STDOUT"/>
    </root>
</configuration>

skywalking警告

这几配置了一些调用约束,一旦达成,就会发出skywalking警告消息,基本上都是时间段内调用时间、失败次数等的约束,而且还是调用指定的回调函数,方便发生警告后,执行一些自定义的方法:

package com.stock1Api.api;/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 *
 */

import lombok.Getter;
import lombok.Setter;

/**
 * Alarm message represents the details of each alarm.
 */
@Setter
@Getter
public class AlarmMessage {
    private int scopeId;
    private String scope;
    private String name;
    private String id0;
    private String id1;
    private String ruleName;
    private String alarmMessage;
    private long startTime;
    private transient boolean onlyAsCondition;

    @Override
    public String toString() {
        return "AlarmMessage{" +
                "scopeId=" + scopeId +
                ", scope='" + scope + '\'' +
                ", name='" + name + '\'' +
                ", id0='" + id0 + '\'' +
                ", id1='" + id1 + '\'' +
                ", ruleName='" + ruleName + '\'' +
                ", alarmMessage='" + alarmMessage + '\'' +
                ", startTime=" + startTime +
                ", onlyAsCondition=" + onlyAsCondition +
                '}';
    }
}
    @PostMapping("/ksysalkingMessage")
    public void ksysalkingMessage(@RequestBody List<AlarmMessage> mesgs) {
        log.info(mesgs.toString());
    }

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

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

相关文章

学python新手如何安装pycharm;python小白如何安装pycharm

首先找到官网&#xff1a; Download PyCharm: The Python IDE for data science and web development by JetBrains 打开后选择下载&#xff0c;下图标红部分 点击exe程序&#xff0c;点击下一步&#xff01; 选择安装路径&#xff0c;下一步 弹出界面全选 选择默认 然后直接…

猜一猜“爵”在古代是哪种器具?2024年3月17日蚂蚁庄园今日答案

蚂蚁庄园是一款爱心公益游戏&#xff0c;用户可以通过喂养小鸡&#xff0c;产生鸡蛋&#xff0c;并通过捐赠鸡蛋参与公益项目。用户每日完成答题就可以领取鸡饲料&#xff0c;使用鸡饲料喂鸡之后&#xff0c;会可以获得鸡蛋&#xff0c;可以通过鸡蛋来进行爱心捐赠。其中&#…

CTF-希尔加解密

对于希尔加解密很多writeup都说用在线工具,所以研究了一下,写了一个方便的加解密python代码,根据给定的字母表及私钥字符串,尝试不同纬度不同重叠的加密矩阵输出加解密结果。运行效果如下: 代码文件Hill希尔加解密_final.py import numpy as np import string # 导入自定…

ArcGIS模型构建器Pro版_更多花活演示

相比较ArcMap的模型构建器&#xff0c;Pro里最主要的变化就是增加了一组逻辑工具&#xff1a; 逻辑工具用于控制模型中的流程流&#xff0c;它们返回的结果是true或false。 这个结果一般用于 if-else 分支逻辑&#xff0c;例如&#xff1a;如果某字段存在的时候&#xff0c;执…

从零开始学习编程:迈出你的编程之路

标题 《从零开始学习编程&#xff1a;迈出你的编程之路》摘要引言如何开始学习编程&#xff1f;1. **明确学习目标**2. **选择编程语言**3. **学习资源**4. **练习编程**5. **参与社区**6. **持之以恒**7. **探索更多** 总结参考资料 博主 默语带您 Go to New World. ✍ 个人主…

刷题DAY25 | LeetCode 216-组合总和III 17-电话号码的字母组合

216 组合总和III&#xff08;medium&#xff09; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 …

unicloud update 修改

update 修改 使用腾讯云时更新方法必须搭配doc、where方法使用&#xff0c;db.collection(‘test’).update()会报如下错误&#xff1a;param should have required property ‘query’ collection.doc().update(Object data)未使用set、remove更新操作符的情况下&#xff0c…

计算机网络实训-2 网络设备配置基础

文章目录 一、交换机/路由器的内部组成二、接口类型及接口标识观察&#xff1a;交换机、路由器的外观交换机的接口标识交换机的接口标识举例 路由器的接口标识路由器的接口标识举例 三、配置交换机/路由器的方法通过Console口来配置&#xff08;带外管理&#xff09;通过telnet…

【vue baidu-map】实现百度地图展示基地,鼠标悬浮标注点展示详细信息

实现效果如下&#xff1a; 自用代码记录 <template><div class"map" style"position: relative;"><baidu-mapid"bjmap":scroll-wheel-zoom"true":auto-resize"true"ready"handler"><bm-mar…

XCTF:level0[WriteUP]

PWN入门题目&#xff1a;XCTF攻防世界的level0 使用file、checksec命令查看文件详细信息 这是一个64bit的ELF文件&#xff08;后面编写EXP需要用到&#xff09; 从checksec中展示的信息看&#xff0c;该二进制文件只开启了NX&#xff08;数据执行保护&#xff09; 这样的话就…

如何理解Linux文件IO?

一、文件IO的概述 1、什么是文件&#xff1f; Linux下一切皆文件。普通文件、目录文件、管道文件、套接字文件、链接文件、字符设备文件、块设备文件。 2、什么是IO&#xff1f; input output&#xff1a;输入输出 3、什么是文件IO&#xff1f; 对文件的输入输出&#xff0c;把…

Radware DDoS防护迎来重大升级,重拳出击在线游戏行业难题

日前&#xff0c;全球领先的网络安全和应用交付解决方案提供商Radware推出了多维DDoS检测和防护措施&#xff0c;以满足在线游戏行业独特复杂的需求。Radware开发了一系列新的算法来保护在线游戏免遭复杂攻击。 Radware首席运营官Gabi Malka表示&#xff1a;“在线游戏是价值数…

【海贼王的数据航海】排序——概念|直接插入排序|希尔排序

目录 1 -> 排序的概念及其运用 1.1 -> 排序的概念 1.2 -> 常见的排序算法 2 -> 插入排序 2.1 -> 基本思想 2.2 -> 直接插入排序 2.2.1 -> 代码实现 2.3 -> 希尔排序(缩小增量排序) 2.3.1 -> 代码实现 1 -> 排序的概念及其运用 1.1 -&g…

Centos7安装Clickhouse单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

SQLite数据库使用指南以及相关API编程

SQLite介绍 SQLite是一种基于C语言开发的轻量级、快速、自包含、高可靠性和全功能的SQL数据库引擎。它是全球范围内使用最为广泛的数据库引擎&#xff0c;被嵌入到所有移动设备和大部分计算机中&#xff0c;并且伴随着无数日常使用的应用程序一起提供。SQLite的文件格式具有稳…

免费阅读篇 | 芒果YOLOv8改进110:注意力机制GAM:用于保留信息以增强渠道空间互动

&#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 该专栏完整目录链接&#xff1a; 芒果YOLOv8深度改进教程 该篇博客为免费阅读内容&#xff0c;直接改进即可&#x1f680;&#x1f680;&#x1f…

论文阅读——Rein

Stronger, Fewer, & Superior: Harnessing Vision Foundation Models for Domain Generalized Semantic Segmentation 一、引言 是一个对Domain Generalized Semantic Segmentation (DGSS)任务的视觉大模型的微调方法&#xff0c;即Rein。 Rein 专为 DGSS 任务量身定制&a…

Linux操作系统裸机开发-环境搭建

一、配置SSH服务 1、下载安装ssh服务输入以下命令 sudo apt-get install nfs-kernel-server portmap2、建立一个供SSH服务使用的文件夹如以下命令 mkdir linux 3、完成前两步之后需要将其文件路径放到/etc/exports文件里输入以下命令&#xff1a; sudo vi /etc/esports 4.打…

04-java基础--流程控制语句

一、switch语句 二、循环的三种结构 流程控制语句分为三种结构&#xff1a; 顺序结构&#xff08;按代码的书写顺序执行&#xff0c;从上到下依次执行&#xff09;分支结构&#xff08;if语句、if–else语句、switch语句&#xff09;循环结构&#xff08;while、for循环、do–…

超越 GPT4,科大讯飞,再出王炸!

哈喽&#xff0c;大家好&#xff01; 去年&#xff0c;科大讯飞星火大模型上线&#xff0c;给大家推荐了一波&#xff0c;演示了其强大的功能&#xff0c;不少小伙伴都立马申请体验了一把&#xff0c;也有私信说非常强大&#xff0c;工作效率提高不少&#xff0c;支持国产大模…