# spring-cloud **Repository Path**: qiao_jin_zhou/spring-cloud ## Basic Information - **Project Name**: spring-cloud - **Description**: 后端java项目学习代码【SpringCloud】 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-02-11 - **Last Updated**: 2025-04-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringCloud, 学习 ## README # Spring Cloud 系列教程 1. Spring Cloud Consul^Alibaba Nacos 服务注册与发现 2. Spring Cloud LoadBalancer^Spring Cloud OpenFeign 服务调用和负载均衡 3. Alibaba Seata 分布式事务 4. Spring Cloud Circuit Breaker Resilience4J^Alibaba Sentinel 服务熔断和降级 5. Spring Cloud Sleuth^Micrometer Tracing 服务链路追踪 6. Spring Cloud Gateway 服务网关 7. Alibaba Nacos 分布式配置管理 ## Spring Cloud Consul 服务注册与发现 _[Consul官方安装地址](https://developer.hashicorp.com/consul/install)_ ### consul pom 依赖 ``` xml org.springframework.cloud spring-cloud-starter-consul-discovery commons-logging commons-logging org.springframework.cloud spring-cloud-starter-bootstrap org.springframework.cloud spring-cloud-starter-consul-config commons-logging commons-logging ``` #### consul 启动本地服务 ``` shell consul agent -dev ``` #### consul 本地持久化服务 * ##### 创建consul-config.json文件,内容如下: ``` json { "data_dir": "/Users/qiaojinzhou/Desktop/项目软件/project-01/consul-data", "ui": true, "server": true, "bootstrap_expect": 1, "bind_addr": "127.0.0.1", "client_addr": "127.0.0.1", "retry_join": ["provider=virtualbox"] } ``` * ##### 启动consul自定义配置服务 ``` shell consul agent -config-file=consul-config.json ``` #### consul 查看文件路径 ``` shell brew --prefix consul ``` #### consul yml 配置 * ##### 消费者服务配置 application.yml ``` yml spring: application: name: cloud-consumer-feign-order cloud: consul: host: localhost port: 8500 discovery: prefer-ip-address: true # 访问地址用ip地址 service-name: ${spring.application.name} ``` * ##### 提供者服务配置 bootstrap.yml ``` yml spring: application: name: cloud-payment-service cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name} config: profile-separator: '-' format: YAML watch: wait-time: 1 # consul监听超时时间 默认55s ``` #### consul 开启服务发现 ``` java @EnableDiscoveryClient ``` #### consul 动态刷新配置 ``` java @RefreshScope ``` #### consul 开启负载均衡 ###### 使用@LoadBalanced注解的RestTemplate进行服务调用 ``` java @Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } ``` ## Spring Cloud LoadBalancer^Spring Cloud OpenFeign 服务调用和负载均衡 _[LoadBalancer官网文档](https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html)_ ### loadbalancer pom 依赖 ``` xml org.springframework.cloud spring-cloud-starter-loadbalancer ``` #### loadbalancer 指定负载均衡算法 * ##### 自定义负载均衡算法 ``` java @LoadBalancerClient(value = "cloud-payment-service", configuration = RestTemplateConfig.class) ``` * ##### 负载均衡算法配置 ``` java @Bean ReactorLoadBalancer randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class), name); } ``` #### loadbalancer 方法调用 * ##### 获取所有服务实例 ``` java List services = discoveryClient.getServices(); ``` * ##### 获取指定服务实例 ``` java List instances = discoveryClient.getInstances("cloud-payment-service"); ``` * ##### 获取指定服务实例信息 地址 端口 主机名 服务id ``` java instances.get(0).getServiceId() + ":" + instances.get(0).getPort() + "\t" + instances.get(0).getUri() + "\t" + instances.get(0).getHost(); ``` ### openfeign pom 依赖 ``` xml org.springframework.cloud spring-cloud-starter-openfeign ``` #### openfeign 开启服务调用 ``` java @EnableFeignClients ``` #### openfeign 指定服务调用 ``` java @FeignClient(value = "cloud-payment-service") public interface PayFeignApi { } ``` #### openfeign 超时时间配置 ###### default(全局配置) cloud-payment-service(指定配置) ``` yml spring: cloud: openfeign: client: config: default: connect-timeout: 3000 read-timeout: 3000 cloud-payment-service: connect-timeout: 3000 read-timeout: 3000 ``` #### openfeign 超时重试机制策略 ``` java @Configuration public class FeignConfig { @Bean public Retryer feignRetryer() { //return Retryer.NEVER_RETRY; //默认配置不走重试策略 //重试间隔时间,重试次数,重试最大时间 return new Retryer.Default(100, 1, 3); } } ``` #### openfeign apache httpclient5 pom依赖 ###### 替换默认的openfeign HttpUrlConnection为apache httpclient5 ``` xml org.apache.httpcomponents.client5 httpclient5 5.3 io.github.openfeign feign-hc5 13.1 ``` #### openfeign apache httpclient5 开启配置 ``` yml spring: cloud: openfeign: httpclient: hc5: enabled: true ``` #### openfeign compression 压缩配置 ``` yml spring: cloud: openfeign: compression: request: enabled: true # 开启请求压缩 mime-types: application/json,text/xml,application/xml # 压缩类型 min-request-size: 2048 # 压缩最小值 response: enabled: true # 开启响应压缩 ``` #### openfeign 日志配置 * ##### 开启日志配置 feign 设置日志级别 ###### NONE 不记录任何信息 ###### BASIC 只记录请求方法、URL以及响应状态码和执行时间 ###### HEADERS 除了记录基本信息外,还会记录请求和响应的头信息 ###### FULL 记录所有请求和响应的明细,包括头信息、请求体、元数据等 ``` java @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; //默认配置打印所有请求 } } ``` * ##### feign日志以什么级别监控那个接口 ``` yml logging: level: com: qiaojinzhou: test: apis: PayFeignApi: debug ``` ## Spring Cloud Circuit Breaker Resilience4J 服务熔断和降级 _[Circuit Breaker](https://spring.io/projects/spring-cloud-circuitbreaker)_ ### Circuit Breaker resilience4j pom 依赖 ``` xml org.springframework.cloud spring-cloud-starter-circuitbreaker-resilience4j org.springframework.boot spring-boot-starter-aop ``` #### Circuit Breaker resilience4j circuitbreaker 开启断路器和断路器配置 按照请求次数配置 ``` yml spring: cloud: openfeign: circuitbreaker: enabled: true # 开启断路器 group: enabled: true # 开启断路器组 resilience4j: # resilience4j 断路器配置 按照请求次数配置 circuitbreaker: configs: default: # 默认配置 failureRateThreshold: 50 # 失败率达到多少后熔断 slidingWindowType: COUNT_BASED # 滑动窗口类型 slidingWindowSize: 6 # 滑动窗口大小 minimumNumberOfCalls: 6 # 最小请求数 automaticTransitionFromOpenToHalfOpenEnabled: true # 开启自动切换半开状态 waitDurationInOpenState: 5s # 熔断持续时间 permittedNumberOfCallsInHalfOpenState: 2 # 半开状态允许的请求数 recordExceptions: # 哪些异常需要记录 - java.lang.Exception # 记录所有异常 instances: # 实例配置 cloud-payment-service: # 服务名 baseConfig: default # 使用默认配置 ``` #### Circuit Breaker resilience4j circuitbreaker 开启断路器和断路器配置 按照时间配置 ``` yml spring: cloud: openfeign: circuitbreaker: enabled: true # 开启断路器 group: enabled: true # 开启断路器组 resilience4j: # resilience4j 断路器配置 按照时间配置 timelimiter: # resilience4j 超时配置 configs: default: # 默认配置 timeoutDuration: 10s # 超时时间 circuitbreaker: configs: default: # 默认配置 failureRateThreshold: 50 # 失败率达到多少后熔断 slowCallDurationThreshold: 2s # 慢调用时长 slowCallRateThreshold: 30 # 慢调用比例 slidingWindowType: TIME_BASED # 滑动窗口类型 slidingWindowSize: 2 # 滑动窗口大小 minimumNumberOfCalls: 2 # 最小请求数 waitDurationInOpenState: 5s # 熔断持续时间 permittedNumberOfCallsInHalfOpenState: 2 # 半开状态允许的请求数 recordExceptions: # 哪些异常需要记录 - java.lang.Exception # 记录所有异常 instances: # 实例配置 cloud-payment-service: # 服务名 baseConfig: default # 使用默认配置 ``` #### Circuit Breaker resilience4j circuitbreaker 熔断降级接口服务调用 ``` java @RestController public class OrderCircuitController { @Resource private PayFeignApi payFeignApi; @GetMapping("/feign/pay/circuit/{id}") @CircuitBreaker(name = "cloud-payment-service", fallbackMethod = "myCircuitBreakerFallback") public String myCircuitBreaker(@PathVariable("id") Integer id) { return payFeignApi.myCircuit(id); } // 熔断降级兜底方法 public String myCircuitBreakerFallback(Integer id ,Throwable throwable) { // 熔断降级处理逻辑 return "myCircuitBreakerFallback: " + throwable.getMessage(); } } ``` #### Circuit Breaker resilience4j bulkhead 引入pom依赖 (舱壁隔离) ``` xml io.github.resilience4j resilience4j-bulkhead ``` #### Circuit Breaker resilience4j bulkhead 舱壁隔离配置 信号量配置 ``` yml resilience4j: # resilience4j 舱壁隔离 信号量配置 bulkhead: # bulkhead 熔断配置 configs: default: maxConcurrentCalls: 2 # 最大并发数 maxWaitDuration: 1s # 最大等待时间 instances: cloud-payment-service: # 服务名 baseConfig: default # 使用默认配置 timelimiter: # resilience4j 超时配置 configs: default: timeoutDuration: 20s # 超时时间 ``` #### Circuit Breaker resilience4j bulkhead 舱壁隔离接口服务调用 (Semaphore 信号量隔离) ``` java @RestController public class OrderCircuitController { @Resource private PayFeignApi payFeignApi; // 舱壁隔离 SEMAPHORE=信号量 @GetMapping("/feign/pay/bulkhead/{id}") @Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadFallback", type = Bulkhead.Type.SEMAPHORE) public String myBulkhead(@PathVariable("id") Integer id) { return payFeignApi.myBulkhead(id); } // 舱壁隔离兜底方法 public String myBulkheadFallback(Integer id ,Throwable throwable) { //舱壁隔离处理逻辑 return "myBulkheadFallback: " + throwable.getMessage(); } } ``` #### Circuit Breaker resilience4j bulkhead 舱壁隔离配置 线程池配置 ###### spring.cloud.openfeign.circuitbreaker.group.enabled 请设置为false 新线程隔离不支持断路器组 ``` yml resilience4j: # resilience4j 舱壁隔离 线程池配置 timelimiter: # resilience4j 超时配置 configs: default: timeoutDuration: 10s # 超时时间 thread-pool-bulkhead: # 线程池配置 configs: default: maxThreadPoolSize: 1 # 最大线程数 coreThreadPoolSize: 1 # 核心线程数 queueCapacity: 1 # 队列容量 instances: cloud-payment-service: # 服务名 baseConfig: default # 使用默认配置 ``` #### Circuit Breaker resilience4j bulkhead 舱壁隔离接口服务调用 (ThreadPool 线程池隔离) ``` java @RestController public class OrderCircuitController { @Resource private PayFeignApi payFeignApi; // 舱壁隔离 THREADPOOL=线程池 @GetMapping("/feign/pay/bulkhead/{id}") @Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadPoolFallback", type = Bulkhead.Type.THREADPOOL) public CompletableFuture myBulkheadPool(@PathVariable("id") Integer id) { return CompletableFuture.supplyAsync(() -> payFeignApi.myBulkhead(id)); } // 舱壁隔离兜底方法 public CompletableFuture myBulkheadPoolFallback(Integer id ,Throwable throwable) { // 舱壁隔离处理逻辑 return CompletableFuture.supplyAsync(() -> "myBulkheadPoolFallback: " + throwable.getMessage()); } } ``` #### Circuit Breaker resilience4j rateLimiter 引入pom依赖 (限流器) ``` xml io.github.resilience4j resilience4j-ratelimiter ``` #### Circuit Breaker resilience4j rateLimiter 限流器配置 ``` yml resilience4j: # resilience4j 限流配置 ratelimiter: configs: default: limitForPeriod: 2 # 每秒最多调用次数 limitRefreshPeriod: 1s # 时间窗口 timeoutDuration: 1 # 超时时间 instances: cloud-payment-service: baseConfig: default ``` #### Circuit Breaker resilience4j rateLimiter 限流器接口服务调用 ``` java @RestController public class OrderCircuitController { @Resource private PayFeignApi payFeignApi; // 服务限流 @GetMapping("/feign/pay/ratelimit/{id}") @RateLimiter(name = "cloud-payment-service", fallbackMethod = "myRatelimitFallback") public String myBulkhead(@PathVariable("id") Integer id) { return payFeignApi.myRatelimit(id); } // 服务限流兜底方法 public String myRatelimitFallback(Integer id ,Throwable throwable) { // 服务限流处理逻辑 return "myRatelimitFallback: " + throwable.getMessage(); } } ``` ## Spring Cloud Micrometer Tracing 微服务链路追踪(ZipKin 图形展示& Micrometer 数据采集) ### ZipKin 链路追踪图形化工具 _[zipkin官方安装地址](https://zipkin.io/pages/quickstart.html)_ #### ZipKin 启动命令 ``` shell java -jar zipkin-server-3.5.0-exec.jar ``` ### Micrometer 引入pom父依赖(父工程) ``` xml io.micrometer micrometer-tracing-bom 1.2.0 pom import io.micrometer micrometer-tracing 1.2.0 io.micrometer micrometer-tracing-bridge-brave 1.2.0 io.micrometer micrometer-observation 1.12.0 io.github.openfeign feign-micrometer 12.5 io.zipkin.reporter2 zipkin-reporter-brave 2.17.0 ``` #### Micrometer 引入pom子依赖 (子工程) ``` xml io.micrometer micrometer-tracing io.micrometer micrometer-tracing-bridge-brave io.micrometer micrometer-observation io.github.openfeign feign-micrometer io.zipkin.reporter2 zipkin-reporter-brave ``` #### Micrometer yml 配置 (子工程) ``` yml management: # 监控配置 zipkin: # 链路追踪 tracing: # 采样 endpoint: http://localhost:9411/api/v2/spans # 链路追踪地址 tracing: sampling: probability: 1.0 # 采样率 ``` ## Spring Cloud Gateway 服务网关 _[Gateway官方文档地址](https://spring.io/projects/spring-cloud-gateway)_ ### Gateway 引入pom依赖 ``` xml org.springframework.cloud spring-cloud-starter-gateway ``` ### Gateway yml 配置 ``` yml spring: cloud: gateway: routes: - id: pay_route1 uri: lb://cloud-payment-service predicates: - Path=/pay/gateway/get/** - My=diamond - id: pay_route2 uri: lb://cloud-payment-service predicates: - Path=/pay/gateway/info/** - My=diamond ilters: - AddRequestHeader=X-Request-Id1,Id1 - AddRequestHeader=X-Request-Id2,Id2 - My=qiaojinzhou ``` ### Gateway Predicate 自定义断言 ``` java @Component public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory { public MyRoutePredicateFactory() { super(MyRoutePredicateFactory.Config.class); } @Setter @Getter @Validated public static class Config { @NotEmpty private String userType; } @Override public List shortcutFieldOrder() { return Collections.singletonList("userType"); } @Override public Predicate apply(MyRoutePredicateFactory.Config config) { return new Predicate() { @Override public boolean test(ServerWebExchange serverWebExchange) { String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType"); return config.getUserType().equals(userType); } }; } } ``` ### Gateway Filter 自定义全局过滤器 ``` java @Component @Slf4j public class MyGlobalFilter implements GlobalFilter, Ordered { public static final String BEGIN_VISIT_TIME = "begin_visit_time"; @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis()); return chain.filter(exchange).then( Mono.fromRunnable(() -> { Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME); if (beginVisitTime != null) { log.info("请求地址:{}", exchange.getRequest().getURI()); log.info("请求方法:{}", exchange.getRequest().getMethod()); log.info("请求参数:{}", exchange.getRequest().getQueryParams()); log.info("请求耗时:{}", System.currentTimeMillis() - beginVisitTime); log.info("================================="); System.out.println(); } }) ); } @Override public int getOrder() { return 0; } } ``` ### Gateway Filter 自定义局部过滤器 ``` java @Component public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory { public MyGatewayFilterFactory() { super(MyGatewayFilterFactory.Config.class); } @Override public GatewayFilter apply(MyGatewayFilterFactory.Config config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); System.out.println("MyGatewayFilterFactory.Config.status = " + config.getStatus()); if (request.getQueryParams().containsKey("qiaojinzhou")) { return chain.filter(exchange); } else { exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); return exchange.getResponse().setComplete(); } } }; } @Override public List shortcutFieldOrder() { ArrayList list = new ArrayList<>(); list.add("status"); return list; } @Getter @Setter public static class Config { private String status; } } ``` ## Spring Cloud Alibaba _[Alibaba官方文档地址](https://github.com/alibaba/spring-cloud-alibaba/blob/2023.x/README-zh.md)_ ### Nacos 服务注册与发现 _[Nacos官方文档地址](https://nacos.io/)_ #### Nacos 启动命令&关闭命令 ``` shell sh startup.sh -m standalone sh shutdown.sh ``` #### Nacos 登陆地址 ``` 地址:http://localhost:8848/nacos/ 账户:nacos 密码:nacos ``` #### Nacos 引入pom依赖(生产者) ``` xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery ``` #### Nacos 引入pom依赖(消费者) ``` xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-loadbalancer ``` #### Nacos yml 配置(生产者) ``` yml server: port: 9001 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #Nacos服务注册中心地址 ``` #### Nacos yml 配置(消费者) ``` yml server: port: 83 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 #Nacos服务注册中心地址 service-url: nacos-user-service: http://nacos-payment-provider ``` #### Nacos 配置管理 开启负载均衡(消费者) ``` java @Configuration public class RestTemplateConfig { @Bean @LoadBalanced // 开启负载均衡 public RestTemplate getRestTemplate() { return new RestTemplate(); } } ``` #### Nacos 配置管理 ConfigClient 3377 ##### NacosConfigClient ``` java @RestController @RefreshScope // 监听Nacos配置中心 public class NacosConfigClientController { @Value("${config.info}") private String configInfo; @GetMapping("/config/info") public String getConfigInfo() { return configInfo; } } ``` ##### bootstrap.yml ``` yml spring: application: name: nacos-config-client cloud: nacos: discovery: server-addr: localhost:8848 # Nacos服务注册中心地址 config: server-addr: localhost:8848 # Nacos配置中心地址 file-extension: yaml # 配置后缀名 group: DEFAULT_GROUP # 配置分组 namespace: public # 命名空间 ``` ##### application.yml ``` yml server: port: 3377 spring: profiles: active: dev # 激活开发环境配置 ``` ### Sentinel 服务熔断和降级 _[Sentinel官方地址](https://sentinelguard.io/zh-cn/)_ _[下载包zipkin-server-3.5.0-exec.jar地址](https://github.com/alibaba/Sentinel/releases)_ #### Sentinel 引入pom依赖 ``` xml com.alibaba.cloud spring-cloud-starter-alibaba-sentinel ``` #### Sentinel 配置 ``` yml server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 # Nacos服务端地址 sentinel: transport: #配置Sentinel dashboard地址 dashboard: localhost:8080 #监控地址 port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口 web-context-unify: false # 默认为true,如果为true,则所有请求都会被拦截,包括/actuator/sentinel/**,如果为false,则/actuator/sentinel/**不会被拦截,但/act ``` #### Sentinel 自定义限流规则 ``` java @RestController @Slf4j public class RateLimitController { @GetMapping("/rateLimit/byResource") @SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleBlockHandler") public String byResource() { return "byResource 限流测试"; } public String handleBlockHandler(BlockException blockException) { return "handleBlockHandler 服务不触发了 SentinelResource启动"; } } ``` #### Sentinel 自定义降级规则 ``` java @RestController @Slf4j public class RateLimitController { @GetMapping("/rateLimit/byResource") @SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleBlockHandler", fallback = "handleFallback") public String byResource(@PathVariable("p1") Integer p1) { if (p1 == 0) { throw new RuntimeException("p1不能为0"); } return "byResource"; } public String handleBlockHandler(@PathVariable("p1") Integer p1, BlockException b) { return "handleBlockHandler 服务不触发了 SentinelResource启动:" + b.getMessage(); } public String handleFallback(@PathVariable("p1") Integer p1, Throwable t) { return "handleFallback 服务异常了:" + t.getMessage(); } } ``` #### Sentinel 热点参数限流 ``` java @RestController @Slf4j public class RateLimitController { // 热点参数限流 @GetMapping("/rateLimit/testHotKey") @SentinelResource(value = "testHotKey", blockHandler = "dealHandle_testHotKey") public String testHotKey ( @RequestParam(value = "p1", required = false) String p1, @RequestParam(value = "p2", required = false) String p2) { return "testHotKey"; } public String dealHandle_testHotKey(String p1, String p2, BlockException e) { return "dealHandle_testHotKey"; } } ``` #### Sentinel 自定义授权规则 ``` java @Component public class MyRequestOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest httpServletRequest) { return httpServletRequest.getParameter("serverName"); } } ``` #### Sentinel 自定义规则持久化 ``` xml com.alibaba.csp sentinel-datasource-nacos ``` ``` yml spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 # Nacos服务端地址 sentinel: datasource: ds1: nacos: server-addr: localhost:8848 # Nacos服务端地址 dataId: ${spring.application.name} # 默认为${spring.application.name}-sentinel groupId: DEFAULT_GROUP # 默认为DEFAULT_GROUP data-type: json # 默认为json rule-type: flow # 规则类型,支持flow(流量控制)、degrade(熔断降级)、authority(授权规则)、param-flow(热点参数限流) ``` ### Seata 分布式事务 _[Seata官方地址](https://seata.apache.org/zh-cn/)_ _[Seata下载地址](https://github.com/apache/incubator-seata/releases)_ _[Seata数据表地址](https://github.com/apache/incubator-seata/blob/v2.0.0/script/server/db/mysql.sql)_ #### Seata 文件配置 (seata/conf/application.yml) ``` yml seata: config: # support: nacos, consul, apollo, zk, etcd3 type: nacos nacos: server-addr: 127.0.0.1:8848 group: SEATA_GROUP namespace: username: nacos password: nacos registry: # support: nacos, eureka, redis, zk, consul, etcd3, sofa type: nacos nacos: application: seata-server server-addr: 127.0.0.1:8848 group: SEATA_GROUP namespace: username: nacos password: nacos cluster: default store: # support: file 、 db 、 redis 、 raft mode: db db: datasource: druid db-type: mysql driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false username: qiaojinzhou password: qiaojinzhou min-conn: 10 max-conn: 100 global-table: global_table branch-table: branch_table lock-table: lock_table distributed-lock-table: distributed_lock query-limit: 1000 max-wait: 5000 ``` #### Seata 数据库表 ``` mysql CREATE DATABASE seata; USE seata; ``` [seata锁表地址](https://github.com/apache/incubator-seata/blob/2.0.0/script/server/db/mysql.sql) ``` mysql create database seata_order; create database seata_storage; create database seata_account; ``` [回滚日志表地址](https://github.com/apache/incubator-seata/blob/2.0.0/script/client/at/db/mysql.sql) #### Seata 脚本SQL ###### 分别为order,storage,account 创建对应业务表 t_order,t_storage,t_account ``` mysql create table t_order( `id` bigint(11) not null auto_increment primary key, `user_id` bigint(11) default null comment '用户ID', `product_id` bigint(11) default null comment '产品ID', `count` int(11) default null comment '数量', `money` decimal(11,0) default null comment '金额', `status` int(1) default null comment '订单状态:0=创建中,1=已完成' )engine=innodb auto_increment=1 default charset=utf8; select * from t_order; ``` ``` mysql create table t_account( `id` bigint(11) not null auto_increment primary key comment 'id', `user_id` bigint(11) default null comment '用户ID', `total` decimal(10,0) default null comment '总额度', `used` decimal(10,0) default null comment '已用额度', `residue` decimal(10,0) default '0' comment '剩余额度' )engine=innodb auto_increment=2 default charset=utf8; INSERT INTO t_account(`id`,`user_id`,`total`,`used`,`residue`)VALUES('1','1','1000','0','1000'); select * from t_account; ``` ``` mysql create table t_storage( `id` bigint(11) not null auto_increment primary key comment 'id', `product_id` bigint(11) default null comment '产品ID', `total` int(11) default null comment '总库存', `used` int(11) default null comment '已用库存', `residue` int(11) default '0' comment '剩余库存' )engine=innodb auto_increment=1 default charset=utf8; INSERT INTO t_storage(`id`,`product_id`,`total`,`used`,`residue`)VALUES('1','1','100','0','100'); select * from t_storage; ``` #### Seata 命令行启动 ``` shell sh seata-server.sh -h localhost -p 8091 -e sh seata-server.sh -p 8091 -h 127.0.0.1 -m file ``` #### Seata 命令行停止 ``` shell sh seata-server.sh stop ``` #### Seata 登陆地址 ``` 地址:http://127.0.0.1:7091/ 账户:seata 密码:seata ``` #### Seata 引入pom依赖 ``` xml com.alibaba.cloud spring-cloud-starter-alibaba-seata ``` #### Seata 配置 ``` yml seata: #seata配置 registry: #注册中心配置 type: nacos #注册中心类型 nacos: #nacos注册中心配置 server-addr: localhost:8848 #nacos地址 namespace: "" #默认值public group: SEATA_GROUP #默认值DEFAULT_GROUP application: seata-server #服务名称 tx-service-group: default_tx_group #事务组 service: #服务配置 vgroup-mapping: #服务虚拟分组到事务服务组的映射关系 default_tx_group: default #默认的事务服务组 data-source-proxy-mode: AT #AT模式 ``` #### Seata AT模式 开启事物锁 ``` java @GlobalTransactional(name = "fsp-create-order", rollbackFor = Exception.class) public void create(Order order) { // 此处省略业务代码 } ```