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-servercloud:nacos:#      nacos服务ipserver-addr: 192.168.126.1:8848discovery:#        空间idnamespace: 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 {@AutowiredRestTemplate 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@LoadBalancedpublic RestTemplate getRestTemplate(RestTemplateBuilder builder) {return builder.build();}@Beanpublic 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 {
//直接注入这个接口,调用它的方法@AutowiredopenFeginOrder 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";}@PostConstructprivate 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-servercloud:sentinel:transport:dashboard: localhost:8002nacos:server-addr: 192.168.126.1:8848discovery:namespace: c1102e00-c947-4d0c-8320-b98dc7fae641group: 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 {@Overridepublic 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页面这玩意看运气,我添加了一下午才成功这一次,用代码添加如下:

  @PostConstructpublic static void initParamFlowRule() {//使用这个方式,居然没有调用我指定的限流方法,待解决List<ParamFlowRule> rules = new ArrayList<>();ParamFlowRule rule = new ParamFlowRule();//阈值类型:只支持QPSrule.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-servercloud:sentinel:transport:dashboard: localhost:8002datasource:flow-rule:nacos:server-addr: 192.168.126.1:8848data-id: stock1-server-sentinel-configruleType: flownacos:server-addr: 192.168.126.1:8848discovery:namespace: c1102e00-c947-4d0c-8320-b98dc7fae641group: TEST
feign:sentinel:enabled: true

seata分布式事务搭建:

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

修改配置:

file.con文件


## transaction log store, only used in seata-server
store {## store mode: file、db、redismode = "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 = 5maxConn = 30globalTable = "global_table"branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100maxWait = 5000}}

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

源码文件的这里:

然后是配置到nacos的文件:

registry.conf

registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "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、etcd3type = "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-servercloud:sentinel:transport:dashboard: localhost:8002datasource:flow-rule:nacos:server-addr: 192.168.126.1:8848data-id: stock1-server-sentinel-configruleType: flownacos:server-addr: 192.168.126.1:8848discovery:namespace: c1102e00-c947-4d0c-8320-b98dc7fae641group: TESTalibaba:seata:tx-service-group: my_test_tx_group #事务分组datasource:driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.126.128:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTCusername: rootpassword: 123456
feign:sentinel:enabled: true
mybatis-plus:configuration:map-underscore-to-camel-case: trueauto-mapping-behavior: fulllog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
seata:registry:type: nacosnacos:server-addr: 192.168.126.1:8848 #nacos地址application: seata-server #在nacos中的服务名username: nacos  #nacos账号密码password: nacosgroup: 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 timeoutio.seata.rm.datasource.exec.LockWaitTimeoutException: Global lock wait timeoutat 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: nullat 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 omittedClosing 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 causeio.seata.rm.datasource.exec.LockConflictException: nullat 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-servercloud:gateway:routes:- id: oder_routeuri: lb://order1-serverpredicates:- Path=/oder/**filters:- StripPrefix=1nacos:server-addr: 192.168.126.1:8848discovery:namespace: c1102e00-c947-4d0c-8320-b98dc7fae641group: TEST

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

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

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

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

server:port: 8080
spring:application:name: gateway-servercloud:gateway:discovery:locator:enabled: truenacos:server-addr: 192.168.126.1:8848discovery:namespace: c1102e00-c947-4d0c-8320-b98dc7fae641group: 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 {@Overridepublic 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 {@PostConstructprivate 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;@Overridepublic 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());}

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

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

相关文章

数据库中逻辑运算符的介绍以及优先级表

简介&#xff1a;逻辑运算符主要判断表达式的真假&#xff0c;返回值为1&#xff0c;0&#xff0c;null 其中包含&#xff1a; 逻辑非&#xff1a;not或&#xff01; 逻辑与&#xff1a;and或&& 逻辑或&#xff1a;or或|| 逻辑异或&#xff1a;XOR 1.逻辑非运算 规则…

mac打开exe文件的三大方法 mac怎么运行exe文件 mac打开exe游戏 macbookpro打开exe

exe文件是Windows系统的可执行文件&#xff0c;虽然Mac系统上无法直接打开exe文件&#xff0c;但是你可以在Mac电脑上安装双系统或者虚拟机来实现mac电脑上运行exe文件。除了这两种方法之外&#xff0c;你还可以在Mac电脑上使用类虚拟机软件打开exe文件&#xff0c;这三种方法各…

双指针 | 移动零 | 复写零

1.移动零 题目描述&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 示例&#xff1a; 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]解题思路&#xff1a; right指针一直往后移动&#xff0c;当…

欧洲跨境物流仓库视频监控系统开发的解决方案

中国联通针对仓储物流行业的数字化需求&#xff0c;提供全面的解决方案&#xff0c;特别是在海外仓储领域&#xff0c;我们深谙企业面临的挑战&#xff0c;如预算限制、仓储空间需求以及城郊网络覆盖不足等问题。我们利用自身强大的网络资源和技术实力&#xff0c;为出海仓储企…

redis学习-Hash类型相关命令及特殊情况分析

目录 1. hset KEY key1 value1 key2 value2 ... 2. hget KEY key 3. hgetall KEY 4. hmget KEY key1 key2 ... 5. hkeys KEY 6. hvals KEY 7. hdel KEY key1 key2 ... 8. hlen KEY 9. hexists KEY key 10. hincrby KEY key num 11. hsetnx KEY key value Hash的内部…

实时数仓项目《一》-实时数仓架构

目录 1. 实时数仓与离线数仓 2. 实时数仓需求 3. 架构图 3.1 行为日志处理&#xff1a; 3.2 业务库表处理&#xff1a; 4. 面试题&#xff1a; &#x1f9c0;你们的实时数仓有分层吗&#xff1f; &#x1f9c0;那你们的业务数据呢&#xff1f; &#x1f9c0;那你们的O…

字符分类函数(iscntrl、i是space.....)---c语言

目录 一、定义二、字符分类函数2.1 -iscntrl&#xff08;&#xff09;2.1.1定义2.1.2使用举例 2.2 -isspace&#xff08;&#xff09;2.2.1描述2.2.2使用举例 2.3-isdigit()2.3.1描述2.3.2使用举例 2.4-isxdigit()2.4.1描述 2.5-islower()2.5.1描述2.5.2使用举例 2.6-isupper()…

THM学习笔记—Simple CTF

nmap扫描&#xff0c;发现2222端口很奇怪啊&#xff0c;重新换一种方式扫描2222端口 发现是ssh 先用ftp试试&#xff0c;尝试匿名登录 下载所有文件 发现只有一个ForMitch.txt&#xff0c;告诉我们其账号密码为弱密码&#xff0c;我们猜测Mitch为其用户名&#xff0c;尝试暴力…

MechanicalSoup,一个非常实用的 Python 自动化浏览器交互工具库!

目录 前言 什么是 Python MechanicalSoup 库&#xff1f; 核心功能 使用方法 1. 安装 MechanicalSoup 库 2. 创建 MechanicalSoup 客户端 3. 打开网页并与之交互 实际应用场景 1. 网页自动化测试 2. 网络爬虫与数据提取 3. 网页自动化操作 4. 自动化填写和提交多个表单 5.…

V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

EPICS和Arduino Uno之间基于串行文本协议的控制开发

Arduino Uno的串口服务程序设置如文本的串口通信协议设计以及在Arduino上的应用-CSDN博客中所示。通过在串口上发送约定的文本协议&#xff0c;它实现的功能如下&#xff1a; 实现功能&#xff1a; 读取三路0.0V~5.0V模拟量输入&#xff0c;读取端口A0~A2设置三路0.0V~5.0V的模…

typeof 与 instanceof 区别

文章目录 一、typeof二、instanceof三、区别 一、typeof typeof 操作符返回一个字符串&#xff0c;表示未经计算的操作数的类型 使用方法如下&#xff1a; typeof operand typeof(operand)operand表示对象或原始值的表达式&#xff0c;其类型将被返回 举个例子 typeof 1 /…

K8S之持久化存储

持久化存储 支持的持久化存储类型EmptyDirHostPathNFS 在K8S中部署的应用都是以pod容器的形式运行的&#xff0c;假如部署数据库服务 例如&#xff1a;MySQL、Redis等&#xff0c;需要对产生的数据做备份。如果pod不挂载数据卷&#xff0c;那pod被删除或重启后这些数据会随之消…

Windows server Database 2025 安装 i225/i226 网卡驱动

windows这比坏得很&#xff0c;intel消费级网卡不准在服务器系统上安装。你要说他是异构不支持&#xff1f;他就纯粹恶心人。 之前已经安装过一次&#xff0c;但是今天database预览版一更新&#xff0c;又给我把网卡驱动杀了&#xff0c;气死&#xff0c;写一篇教程。 1.去官网…

SQLite优化实践:数据库设计、索引、查询和分库分表策略

文章目录 一、数据库设计优化1.1 合理选择数据类型1.2 使用NOT NULL约束1.3 使用默认值1.4 避免使用过多的列 二、索引优化2.1 为经常用于查询条件的列创建索引2.2 为经常用于排序和分组的列创建索引2.3 避免过多的索引2.4 使用覆盖索引 三、查询优化3.1 使用预编译语句3.2 优化…

​​SQLiteC/C++接口详细介绍之sqlite3类(十一)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十二&#xff09;&#xff08;未发表&#xff09; 33.sq…

C语言学习过程总结(18)——指针(6)

一、数组指针变量 在上一节中我们提到了&#xff0c;指针数组的存放指针的数组&#xff0c;那数组指针变量是什么呢&#xff1f; 显而易见&#xff0c;数组指针变量是指针 同样类比整型指针变量和字符指针变量里面分别存放的是整型变量地址和字符变量地址&#xff0c;我们可以…

Helm的资源安装和基本使用

目录 一.Helm的出现 二.Helm工具 1.部署helm 2.helm可用命令介绍 三.chart 1.添加、查看、删除存储库 2.查找chart、查看chart信息、安装chart等 3.安装chart后产生的release 四.安装mysql举例 1.固定chart安装 2.自定义chart安装 一.Helm的出现 在前面的k8s部署po…

13. C++类的简单理解

全面理解C中的类 1. 类的访问属性&#xff1a;public&#xff0c;protect&#xff0c;private C中类的成员变量和函数都带有三种属性中的一种&#xff0c;假如没有特别声明&#xff0c;那么就默认是私有的&#xff08;除了构造函数&#xff09;。public表示是公开的&#xff…

[WUSTCTF2020]颜值成绩查询 --不会编程的崽

这题也是一个很简单的盲注题目&#xff0c;这几天sql与模板注入做麻了&#xff0c;也是轻松拿捏。 它已经提示&#xff0c;enter number&#xff0c;所有猜测这里后台代码并没有使用 " 闭合。没有明显的waf提示&#xff0c; 但是or&#xff0c;and都没反应。再去fuzz一…