父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-serverksysalking的服务端口号
-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()); }