首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,649 阅读
2
Mac打印机设置黑白打印
5,043 阅读
3
修改elementUI中el-table树形结构图标
4,946 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,705 阅读
5
intelliJ Idea 2022.2.X破解
4,459 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Mac
Spring Cloud
MyBatis
WordPress
MacOS
asp.net
Element UI
Nacos
MySQL
.Net
Spring Cloud Alibaba
Mybatis-Plus
Typecho
jQuery
Java Script
IntelliJ IDEA
微信小程序
Laughing
累计撰写
629
篇文章
累计收到
1,421
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
629
篇与
的结果
2021-07-27
Spring Cloud使用Nacos作为服务中心编写服务提供者
在Nacos集群配置中,我们介绍了Nacos的安装以及集群配置,本文我们介绍一下在Spring Cloud中如何使用Nacos作为服务注册中心。编写父工程父工程只提供基本的依赖关系,一定要注意版本,否则会出现很多乱七八糟的错误。父工程依赖如下<?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> <groupId>cc.lisen</groupId> <artifactId>Cloud2020</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>cloud-provider-payment8001</module> <module>cloud-consumer-order80</module> <module>cloud-api-common</module> <module>cloud-provider-payment8004</module> <module>cloud-consumerzk-order80</module> <module>cloud-consumer-feign-order80</module> <module>cloud-provider-hystrix-payment8001</module> <module>cloud-consumer-feign-hystrix-order80</module> <module>cloud-consumer-hystrix-dashboard9001</module> <module>cloud-gateway-gateway9527</module> <module>cloud-config-center-3344</module> <module>cloud-config-client-3355</module> <module>cloud-config-client-3366</module> <module>cloud-stream-rabbitmq-provider8801</module> <module>cloud-stream-rabbitmq-consumer8802</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloud-stream-rabbitmq-consumer8802</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloudalibaba-provider-payment9001</module> <module>cloudalibaba-provider-payment9002</module> <module>cloudalibaba-consumer-order8888</module> <module>cloudalibaba-config-nacos-client3377</module> <module>cloudalibaba-sentinel-service8401</module> <module>seata-order-service2001</module> <module>seata-storage-service2002</module> <module>seata-account-service2003</module> </modules> <!-- 统一管理jar包版本--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <mysql.version>5.1.47</mysql.version> <druid.version>1.1.16</druid.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.12.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR12</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <!-- <version>2.1.0.RELEASE</version>--> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <configuration> <locales>en,fr</locales> </configuration> </plugin> </plugins> </build> <reporting> <plugins> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> </plugin> </plugins> </reporting> </project> 请忽略其他的项目模块。编写服务提供者编写一个简单的服务提供者,输出一个字符串。添加依赖<?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>Cloud2020</artifactId> <groupId>cc.lisen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-provider-payment9002</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.5</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> </project>修改配置文件server: port: 9001 spring: application: name: nacos-provider-payment cloud: nacos: discovery: server-addr: 192.168.120.180:8848 management: endpoints: web: exposure: include: "*"修改启动类@SpringBootApplication public class PaymentProviderMain9001 { public static void main(String[] args){ SpringApplication.run(PaymentProviderMain9001.class,args); } }编写服务接口@RestController @Slf4j public class NacosController { @Value("${server.port}") private String serverPort; @GetMapping(value = "/echo/{string}") public String echo(@PathVariable String string) { return "Hello Nacos Discovery " + string+"\t当前服务端口:"+serverPort; } }启动服务,我们可以查看一下Nacos是否有对应的服务。集群一般情况下,为了系统的健壮性,我们都会进行集群。我这里为了方便调试,复制了一个cloudalibaba-provider-payment9001工程,只是将端口号改成9002,然后,我们启动9002端口项目,再次查看Nacos可以看到当前有两个实例了。集群的关键时服务名称需要一致,也就是我们配置文件中的spring.application.name必须保持一致。
2021年07月27日
1,055 阅读
0 评论
0 点赞
2021-07-27
win一键启动WSL并固定IP
在idea无法访问WSL中Nacos的解决办法一文中,我们介绍了通过nginx端口转发的方式访问WSL中安装的Nacos。但是,如果你又安装了Seata,你会发现用端口映射会报错,这个大家可以自己试一下。其实,我们在使用WSL(我安装的Ubuntu 20.04)时,系统会给我们分配一个IP地址。我们通过ifconfig命令可以查看IP地址。所以,更好的方式,肯定是我们通过这个分配的内网IP进行访问。但是,问题又来了,我们每次重启WSL之后,系统会重新分配以下IP地址,这肯定不是我们想要的结果,不然每个项目光改IP都能疯。同时,每次重启我们如果都执行一边服务启动命令(比如打开ssh、打开nginx、打开mysql等)也比较崩溃。基于此,我们可以设置一个批量命令,一方面启动WSL同时可以自动设置一个固定的IP并开启我们的一些服务。新建一个.bat的文件,粘贴以下内容@echo off setlocal enabledelayedexpansion ::不管三七二十一先停掉可能在跑的wsl实例 wsl --shutdown ubuntu ::重新拉起来,并且用root的身份,启动服务 wsl -u root service ssh start wsl -u root service nginx start wsl -u root service mysql start if !errorlevel! equ 0 ( :: 看看我要的IP在不在 wsl -u root ip addr | findstr "192.168.120.180" > nul if !errorlevel! equ 0 ( echo wsl ip has set ) else ( ::不在的话给安排上 wsl -u root ip addr add 192.168.120.180/24 broadcast 192.168.120.0 dev eth0 label eth0:1 echo set wsl ip success: 192.168.120.180 ) ::windows作为wsl的宿主,在wsl的固定IP的同一网段也给安排另外一个IP ipconfig | findstr "192.168.120.100" > nul if !errorlevel! equ 0 ( echo windows ip has set ) else ( netsh interface ip add address "vEthernet (WSL)" 192.168.120.100 255.255.255.0 echo set windows ip success: 192.168.120.100 ) ) wsl -u root nohup /root/nacos/bin/startup.sh -m standalone >log.out 2>1 & wsl -u root nohup /root/seata/seata-server-1.4.2/bin/seata-server.sh >log.out 2>1 & pause然后右键管理员身份运行,这样,每次我们打开WSL时,就固定了IP地址,并且帮我们运行了服务。
2021年07月27日
2,114 阅读
0 评论
0 点赞
2021-07-27
idea无法访问WSL中Nacos的解决办法
最近在搞微服务的东西,所以在我笔记本上安装了一个WSL(Ubuntu 20.0.4),其实体验还好,只是在网络访问上面遇到了一些问题。一般情况下,我们访问WSL系统的东西时,通过localhost:port的形式即可。比如nginx通过localhost便能正常打开。但是安装Nacos后,通过浏览器能够正常打开但是,在idea中调用时,一直访问不通。{mtitle title="解决办法"/}想着参考集群部署的思路,通过nginx,将1111端口转发到了8848端口,便能正常访问了。修改nginx配置文件,在server节点同级增加以下内容upstream cluster{ server localhost:8848 weight=1; } server { listen 1111; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://cluster; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }然后重启nginx修改项目nacos端口,发现能够成功调用了。
2021年07月27日
2,227 阅读
0 评论
0 点赞
2021-07-27
Ubuntu 20.04换国内源 清华源 阿里源 中科大源 163源
Ubuntu 20.04 是 Ubuntu 的第 8 个 LTS 版本,其重大更新和改进将在 2030 年前终止,计划于2020年 4 月 23 日发布。 国内有很多Ubuntu的镜像源,包括阿里的、网易的,还有很多教育网的源,比如:清华源、中科大源。 我们这里以清华源为例讲解如何修改Ubuntu 20.04里面默认的源。 编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前请做好相应备份):清华源# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse # 预发布软件源,不建议启用 # deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse然后执行sudo apt-get update sudo apt-get upgrade阿里源deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse中科大源deb https://mirrors.ustc.edu.cn/ubuntu/ focal main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ focal main restricted universe multiverse deb https://mirrors.ustc.edu.cn/ubuntu/ focal-updates main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ focal-updates main restricted universe multiverse deb https://mirrors.ustc.edu.cn/ubuntu/ focal-backports main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ focal-backports main restricted universe multiverse deb https://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe multiverse deb https://mirrors.ustc.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse网易163源deb http://mirrors.163.com/ubuntu/ focal main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ focal-security main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ focal-updates main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ focal-proposed main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ focal main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ focal-security main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ focal-updates main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ focal-proposed main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ focal-backports main restricted universe multiverse
2021年07月27日
1,181 阅读
0 评论
0 点赞
2021-07-26
wsl ubuntu 20.0.4安装MySql 5.7
安装依次执行以下命令:sudo apt update sudo apt upgrade sudo apt install libaio1 libtinfo5 libmecab2 libjson-perl python2 python2.7 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar tar xvf mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar rm -f mysql-testsuite_5.7.31-1ubuntu18.04_amd64.deb rm -f mysql-community-test_5.7.31-1ubuntu18.04_amd64.deb sudo dpkg -i mysql-common_5.7.31-1ubuntu18.04_amd64.deb sudo dpkg -i lib*.deb sudo dpkg -i mysql-*.deb然后输入root密码启动MySqlservice mysql start修改远程登录sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf重启服务service mysql restart
2021年07月26日
1,207 阅读
0 评论
0 点赞
2021-07-26
Nacos集群配置
Netflix组件移除说明Netflix公司是目前微服务落地中最成功的公司。它开源了诸如Eureka、Hystrix、Zuul、Feign、Ribbon等等广大开发者所知微服务套件,统称为Netflix OSS。在当时Netflix OSS成为微服务组件上事实的标准。但是微服务兴起不久,也就是在 2018 年前后Netflix公司宣布其核心组件Hystrix、Ribbon、Zuul、Eureka等进入维护状态,不再进行新特性开发,只修 BUG。这直接影响了Spring Cloud项目的发展路线,Spring 官方不得不采取了应对措施,在 2019 年的在 SpringOne 2019 大会中,Spring Cloud宣布 Spring Cloud Netflix 项目进入维护模式,并在 2020 年移除相关的Netflix OSS组件。什么是 Nacos?阿里巴巴在2018年7月份发布Nacos, Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos 支持几乎所有主流类型的服务的发现、配置和管理。Nacos集群及配置前置条件MySql 5.X版本JDK 1.8nginx创建MySql数据库创建一个名称为nacos_config的数据库,然后执行以下数据库预置脚本。/* * Copyright 1999-2018 Alibaba Group Holding Ltd. * * Licensed 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. */ /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info */ /******************************************/ CREATE TABLE `config_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(255) DEFAULT NULL, `content` longtext NOT NULL COMMENT 'content', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', `app_name` varchar(128) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', `c_desc` varchar(256) DEFAULT NULL, `c_use` varchar(64) DEFAULT NULL, `effect` varchar(64) DEFAULT NULL, `type` varchar(64) DEFAULT NULL, `c_schema` text, PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_aggr */ /******************************************/ CREATE TABLE `config_info_aggr` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(255) NOT NULL COMMENT 'group_id', `datum_id` varchar(255) NOT NULL COMMENT 'datum_id', `content` longtext NOT NULL COMMENT '内容', `gmt_modified` datetime NOT NULL COMMENT '修改时间', `app_name` varchar(128) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_beta */ /******************************************/ CREATE TABLE `config_info_beta` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL COMMENT 'content', `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_tag */ /******************************************/ CREATE TABLE `config_info_tag` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', `tag_id` varchar(128) NOT NULL COMMENT 'tag_id', `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL COMMENT 'content', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_tags_relation */ /******************************************/ CREATE TABLE `config_tags_relation` ( `id` bigint(20) NOT NULL COMMENT 'id', `tag_name` varchar(128) NOT NULL COMMENT 'tag_name', `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', `nid` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`nid`), UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = group_capacity */ /******************************************/ CREATE TABLE `group_capacity` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群', `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值', `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_group_id` (`group_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = his_config_info */ /******************************************/ CREATE TABLE `his_config_info` ( `id` bigint(64) unsigned NOT NULL, `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `data_id` varchar(255) NOT NULL, `group_id` varchar(128) NOT NULL, `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL, `md5` varchar(32) DEFAULT NULL, `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `src_user` text, `src_ip` varchar(50) DEFAULT NULL, `op_type` char(10) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`nid`), KEY `idx_gmt_create` (`gmt_create`), KEY `idx_gmt_modified` (`gmt_modified`), KEY `idx_did` (`data_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = tenant_capacity */ /******************************************/ CREATE TABLE `tenant_capacity` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID', `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数', `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表'; CREATE TABLE `tenant_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `kp` varchar(128) NOT NULL COMMENT 'kp', `tenant_id` varchar(128) default '' COMMENT 'tenant_id', `tenant_name` varchar(128) default '' COMMENT 'tenant_name', `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc', `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source', `gmt_create` bigint(20) NOT NULL COMMENT '创建时间', `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info'; CREATE TABLE `users` ( `username` varchar(50) NOT NULL PRIMARY KEY, `password` varchar(500) NOT NULL, `enabled` boolean NOT NULL ); CREATE TABLE `roles` ( `username` varchar(50) NOT NULL, `role` varchar(50) NOT NULL, UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE ); CREATE TABLE `permissions` ( `role` varchar(50) NOT NULL, `resource` varchar(255) NOT NULL, `action` varchar(8) NOT NULL, UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE ); INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE); INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');此脚本sql位于Nacos的conf文件夹下:nacos-mysql.sql修改application.properties文件修改conf/application.properties文件,修改MySQL信息及端口。由于我们演示三个集群,位于一个服务器,所以需要三个端口号,我这里分别设置为3333、4444、5555。server.port=3333 #*************** Config Module Related Configurations ***************# ### If use MySQL as datasource: spring.datasource.platform=mysql ### Count of DB: db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=root db.password=root修改cluster.conf我们这里要三个进行集群,所以输入以下信息localhost:3333 localhost:4444 localhost:5555修改另外两个Nacos我这里复制我刚才修改后的Nacos,然后打开application.properties,将端口号分别修改为4444、5555。测试分别进去三个Nacos的bin文件夹,执行 ./startup.sh -m cluster打开http://localhost:3333/nacos,查看节点列表配置nginx启动三台Nacos后,我们需要配置Nginx进行端口转发,我这里Nginx使用1111端口。打开nginx配置文件vi nginx.conf增加以下内容upstream cluster{ server localhost:3333 weight=1; server localhost:4444 weight=1; server localhost:5555 weight=1; } server { listen 1111; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://cluster; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }重启nginxnginx -s reload进入http://localhost:1111/nacos,查看节点至此,Nacos集群配置完成。
2021年07月26日
1,539 阅读
0 评论
2 点赞
2021-07-26
Seata基础教程下-Spring Cloud Alibaba使用Seata
在seata基础教程上-seata 1.4.2的安装及基于Nacos的配置中,我们基于Nacos完成了Seata的安装及配置,这篇文章我们介绍下在Spring Cloud Alibaba中的使用。环境准备学习本文之前,你应该准备好以下环境。Nacos 2.0.2版本并运行Seata Server 1.4.2版本,配置好Nacos并运行前置知识本文通过Spring Cloud Alibaba,使用Nacos作为服务中心,通过OpenFeign实现服务之间的调用,所以你必须具备以下基础知识:在Spring Cloud中使用Nacos作为服务注册、发现中心的配置及使用。在Spring Cloud中通过OpenFeign实现服务之间的调用。MyBatis的使用。场景描述本文参考尚硅谷阳哥的视频教程,使用最新的Nacos(2.0.2)及Seata(1.4.2),演示用户下单的业务场景,基本流程如下其实业务很简单,用户下单,扣减商品库存表数据然后减去账户余额,如果不是微服务架构,我们一般使用一个系统,基本上一个@Transactional注解就解决了。基于微服务就不同了,我们提供三个微服务,分别为订单服务、库存服务、账户服务,三个服务对应三个数据库,分别为seata_order、seata_storage、seata_account,现在不同业务分布在不同的数据库中,那么我们在进行数据回滚就不太好处理了。Seata的分布式交易解决方案有了Seata就简单了,我们只需要使用一个@GlobalTransactional注解在业务方法上就可以了。Spring Cloud使用Seata创建数据库创建三个数据库,分别为seata_order、seata_storage、seata_account。订单微服务表结构create table t_order ( id bigint auto_increment comment '主键', user_id bigint null comment '用户Id', product_id bigint null, count int null, money decimal(11) null, status int(1) null, constraint t_order_id_uindex unique (id) ); alter table t_order add primary key (id); create table undo_log ( id bigint auto_increment primary key, branch_id bigint not null, xid varchar(100) not null, context varchar(128) not null, rollback_info longblob not null, log_status int not null, log_created datetime not null, log_modified datetime not null, constraint ux_undo_log unique (xid, branch_id) ) charset=utf8;账户微服务表结构create table t_account ( id bigint auto_increment, user_id bigint null, total decimal null, used decimal null, residue decimal null, constraint t_account_id_uindex unique (id) ); alter table t_account add primary key (id); create table undo_log ( id bigint auto_increment primary key, branch_id bigint not null, xid varchar(100) not null, context varchar(128) not null, rollback_info longblob not null, log_status int not null, log_created datetime not null, log_modified datetime not null, constraint ux_undo_log unique (xid, branch_id) ) charset=utf8; INSERT INTO seata_account.t_account (id, user_id, total, used, residue) VALUES (1, 1, 1000, 0, 1000);库存微服务表结构create table t_storage ( id bigint auto_increment, product_id bigint null, total int null, used int null, residue int null comment '剩余库存', constraint t_storage_id_uindex unique (id) ); alter table t_storage add primary key (id); create table undo_log ( id bigint auto_increment primary key, branch_id bigint not null, xid varchar(100) not null, context varchar(128) not null, rollback_info longblob not null, log_status int not null, log_created datetime not null, log_modified datetime not null, constraint ux_undo_log unique (xid, branch_id) ) charset=utf8; INSERT INTO seata_storage.t_storage (id, product_id, total, used, residue) VALUES (2, 1, 100, 0, 100);创建工程工程结构,如下图,请忽略其他模块。{message type="warning" content="一定要注意依赖里面的版本号,不然会出现各种错误。"/}创建父工程父工程用于维护依赖管理,没有具体代码。增加依赖<?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> <groupId>cc.lisen</groupId> <artifactId>Cloud2020</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>cloud-provider-payment8001</module> <module>cloud-consumer-order80</module> <module>cloud-api-common</module> <module>cloud-provider-payment8004</module> <module>cloud-consumerzk-order80</module> <module>cloud-consumer-feign-order80</module> <module>cloud-provider-hystrix-payment8001</module> <module>cloud-consumer-feign-hystrix-order80</module> <module>cloud-consumer-hystrix-dashboard9001</module> <module>cloud-gateway-gateway9527</module> <module>cloud-config-center-3344</module> <module>cloud-config-client-3355</module> <module>cloud-config-client-3366</module> <module>cloud-stream-rabbitmq-provider8801</module> <module>cloud-stream-rabbitmq-consumer8802</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloud-stream-rabbitmq-consumer8802</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloud-stream-rabbitmq-consumer8803</module> <module>cloudalibaba-provider-payment9001</module> <module>cloudalibaba-provider-payment9002</module> <module>cloudalibaba-consumer-order80</module> <module>cloudalibaba-config-nacos-client3377</module> <module>cloudalibaba-sentinel-service8401</module> <module>seata-order-service2001</module> <module>seata-storage-service2002</module> <module>seata-account-service2003</module> </modules> <!-- 统一管理jar包版本--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <mysql.version>5.1.47</mysql.version> <druid.version>1.1.16</druid.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.12.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR12</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <!-- <version>2.1.0.RELEASE</version>--> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <configuration> <locales>en,fr</locales> </configuration> </plugin> </plugins> </build> <reporting> <plugins> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> </plugin> </plugins> </reporting> </project> 创建通用模块通用模块这里维护了一个CommonResult用于返回Json对象。增加依赖<?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>Cloud2020</artifactId> <groupId>cc.lisen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-api-common</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.5</version> </dependency> </dependencies> </project>增加实体package cc.lisen.springcloud.entites; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 博客:https://lisen.cc * Description: * * @Author: 李森的博客 * DateTime: 2021-07-24 11:25 */ @Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T> { private Integer code; private String message; private T data; public CommonResult(Integer code, String message) { this(code, message, null); } }创建订单微服务模块订单模块维护订单微服务,通过Feign调用库存及账户微服务。增加依赖<?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>Cloud2020</artifactId> <groupId>cc.lisen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>seata-order-service2001</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.5</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>cc.lisen</groupId> <artifactId>cloud-api-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>修改配置文件配置文件一定要注意,tx-service-group一定要与我们Seata服务端的配置保持一致。server: port: 2001 spring: application: name: seata-order-service cloud: nacos: discovery: server-addr: localhost:1111 loadbalancer: retry: enabled: false datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/seata_order?useSSL=false username: root password: root feign: hystrix: enabled: false mybatis: type-aliases-package: cc.lisen.springcloud.alibaba.seata.domain mapperLocations: classpath:/mapper/*.xml seata: tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 service: vgroup-mapping: my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 config: type: nacos nacos: server-addr: localhost:1111 group: "SEATA_GROUP" namespace: "" username: "nacos" password: "nacos"增加实体@Data @AllArgsConstructor @NoArgsConstructor public class Order { /** * 主键 */ private Long id; /** * 用户Id */ private Long userId; private Long productId; private Integer count; private BigDecimal money; private Integer status; }增加Mapperpublic interface OrderDao { int create(Order record); int update(@Param("userId") Long userId, @Param("status") Integer status);数据库操作<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.lisen.springcloud.alibaba.seata.dao.OrderDao"> <resultMap id="BaseResultMap" type="cc.lisen.springcloud.alibaba.seata.domain.Order"> <!--@Table t_order--> <result column="id" jdbcType="BIGINT" property="id"/> <result column="user_id" jdbcType="BIGINT" property="userId"/> <result column="product_id" jdbcType="BIGINT" property="productId"/> <result column="count" jdbcType="INTEGER" property="count"/> <result column="money" jdbcType="DECIMAL" property="money"/> <result column="status" jdbcType="INTEGER" property="status"/> </resultMap> <sql id="Base_Column_List"> <!--@mbg.generated--> id, user_id, product_id, `count`, money, `status` </sql> <insert id="create" parameterType="cc.lisen.springcloud.alibaba.seata.domain.Order"> <!--@mbg.generated--> insert into t_order (user_id, product_id, `count`, money, `status`) values (#{userId,jdbcType=BIGINT}, #{productId,jdbcType=BIGINT}, #{count,jdbcType=INTEGER}, #{money,jdbcType=DECIMAL}, #{status,jdbcType=INTEGER}) </insert> <update id="update"> update t_order set status = 1 where user_id = #{userId} and status = #{status} </update> </mapper>增加服务接口增加账户微服务Feign调用接口@FeignClient(value = "seata-account-service") public interface IAccountService { @PostMapping("/account/decrease") public CommonResult accountDecrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money); }增加库存微服务Feign调用接口@FeignClient(value = "seata-storage-service") public interface IStorageService { @PostMapping("/storage/decrease") public CommonResult storageDecrease(@RequestParam("productId") Long productId,@RequestParam("count") Integer count); } 增加订单接口public interface IOrderService { int create(Order record); }增加订单服务实现@Service @Slf4j public class OrderServiceImpl implements IOrderService { @Resource private OrderDao orderDao; @Resource private IStorageService storageService; @Resource private IAccountService accountService; @Override @GlobalTransactional(name = "fsp-create-order") // @Transactional public int create(Order order) { log.info("--------->开始新建订单"); orderDao.create(order); log.info("--------->订单微服务开始调用库存,做扣减Count"); storageService.storageDecrease(order.getProductId(), order.getCount()); log.info("--------->订单微服务开始调用库存,做扣减End"); log.info("--------->订单微服务开始调用账户,做扣减Money"); accountService.accountDecrease(order.getUserId(), order.getMoney()); log.info("--------->订单微服务开始调用账户,做扣减End"); log.info("--------->修改订单状态开始"); orderDao.update(order.getUserId(), 0); log.info("--------->修改订单状态End"); return 1; } }增加接口controller@RestController @Slf4j @RequestMapping("/order") public class OrderController { @Resource private IOrderService orderService; @PostMapping("/create") public CommonResult create(Order order) { orderService.create(order); return new CommonResult(200, "订单创建成功"); } }增加DataSource,让Seata代理数据库@Configuration public class DataSourceProxyConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ return new DruidDataSource(); } }修改启动类取消数据源自动配置,让Seata能够代理数据源。@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableDiscoveryClient @EnableFeignClients @MapperScan(basePackages = {"cc.lisen.springcloud.alibaba.seata.dao"}) public class SeataOrderServiceMain2001 { public static void main(String[] args) { SpringApplication.run(SeataOrderServiceMain2001.class, args); } }创建库存微服务模块库存微服务用于提供扣减库存的微服务接口。增加依赖<?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>Cloud2020</artifactId> <groupId>cc.lisen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>seata-storage-service2002</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.5</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>cc.lisen</groupId> <artifactId>cloud-api-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>修改配置文件server: port: 2002 spring: application: name: seata-storage-service cloud: nacos: discovery: server-addr: localhost:1111 loadbalancer: retry: enabled: false datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/seata_storage?useSSL=false username: root password: root feign: hystrix: enabled: false mybatis: type-aliases-package: cc.lisen.springcloud.alibaba.seata.domain mapperLocations: classpath:/mapper/*.xml seata: tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 service: vgroup-mapping: my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 config: type: nacos nacos: server-addr: localhost:1111 group: "SEATA_GROUP" namespace: "" username: "nacos" password: "nacos"增加实体@Data @AllArgsConstructor @NoArgsConstructor public class Storage { private Long id; private Long productId; private Integer total; private Integer used; private Integer residue; }增加Mapperpublic interface StorageDao { int decrease(@Param("productId") Long productId, @Param("count") Integer count); }数据库操作<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.lisen.springcloud.alibaba.seata.dao.StorageDao"> <resultMap id="BaseResultMap" type="cc.lisen.springcloud.alibaba.seata.domain.Storage"> <!--@Table t_storage--> <result column="id" jdbcType="BIGINT" property="id"/> <result column="product_id" jdbcType="BIGINT" property="productId"/> <result column="total" jdbcType="INTEGER" property="total"/> <result column="used" jdbcType="INTEGER" property="used"/> <result column="residue" jdbcType="INTEGER" property="residue"/> </resultMap> <sql id="Base_Column_List"> id, product_id, total, used, residue </sql> <update id="decrease"> update t_storage set used = used + #{count}, residue = residue - #{count} where product_id = #{productId} </update> </mapper>增加服务接口public interface IStorageService { int decrease(Long productId, Integer count); } 增加服务实现@Service @Slf4j public class StorageServiceImpl implements IStorageService { @Resource private StorageDao storageDao; @Override // @Transactional public int decrease(Long productId, Integer count) { log.info("--------->storage-------decrease获取xid:" + RootContext.getXID()); return storageDao.decrease(productId, count); } }增加接口controller@RestController @RequestMapping("/storage") @Slf4j public class StorageController { @Resource private IStorageService storageService; @PostMapping("/decrease") public CommonResult decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count) { storageService.decrease(productId, count); return new CommonResult(200, "扣减库存成功"); } }增加DataSource,让Seata代理数据源@Configuration public class DataSourceProxyConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ return new DruidDataSource(); } }修改启动类取消数据源自动配置,让Seata能够代理数据源。@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableDiscoveryClient @EnableFeignClients @MapperScan(basePackages = {"cc.lisen.springcloud.alibaba.seata.dao"}) public class SeataStorageServiceMain2002 { public static void main(String[] args) { SpringApplication.run(SeataStorageServiceMain2002.class, args); } }创建账户微服务模块账户微服务用于提供扣减账户金额的微服务接口。增加依赖<?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>Cloud2020</artifactId> <groupId>cc.lisen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>seata-account-service2003</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.5</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>cc.lisen</groupId> <artifactId>cloud-api-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>修改配置文件server: port: 2003 spring: application: name: seata-account-service cloud: nacos: discovery: server-addr: localhost:1111 loadbalancer: retry: enabled: false datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/seata_account?useSSL=false username: root password: root feign: hystrix: enabled: false mybatis: type-aliases-package: cc.lisen.springcloud.alibaba.seata.domain mapperLocations: classpath:/mapper/*.xml seata: tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 service: vgroup-mapping: my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致 config: type: nacos nacos: server-addr: localhost:1111 group: "SEATA_GROUP" namespace: "" username: "nacos" password: "nacos"增加实体@Data @AllArgsConstructor @NoArgsConstructor public class Account { private Long id; private Long userId; private Long total; private Long used; private Long residue; }增加Mapperpublic interface AccountDao { int decrease(@Param("userId") Long userId, @Param("money") BigDecimal money); }数据库操作<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.lisen.springcloud.alibaba.seata.dao.AccountDao"> <resultMap id="BaseResultMap" type="cc.lisen.springcloud.alibaba.seata.domain.Account"> <!--@Table t_account--> <result column="id" jdbcType="BIGINT" property="id"/> <result column="user_id" jdbcType="BIGINT" property="userId"/> <result column="total" jdbcType="DECIMAL" property="total"/> <result column="used" jdbcType="DECIMAL" property="used"/> <result column="residue" jdbcType="DECIMAL" property="residue"/> </resultMap> <sql id="Base_Column_List"> id, user_id, total, used, residue </sql> <update id="decrease"> update t_account set used = used + #{money}, residue=residue - #{money} where user_id = #{userId} </update> </mapper>增加服务接口public interface IAccountService { int decrease( Long userId, BigDecimal money); }增加服务实现这里注意以下,我们模拟了报错信息@Service @Slf4j public class AccountServiceImpl implements IAccountService { @Resource private AccountDao accountDao; @Override // @Transactional public int decrease(Long userId, BigDecimal money) { log.info("--------->storage-------decrease获取xid:" + RootContext.getXID()); //模拟报错 int age = 10 / 0; return accountDao.decrease(userId, money); } }增加接口controller@RestController @Slf4j @RequestMapping("/account") public class AccountController { @Resource private IAccountService accountService; @PostMapping("/decrease") public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money) { accountService.decrease(userId, money); return new CommonResult(200, "账户扣减成功"); } }增加DataSource,让Seata代理数据源@Configuration public class DataSourceProxyConfig { @Value("${mybatis.mapperLocations}") private String mapperLocations; @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ return new DruidDataSource(); } }修改启动类取消数据源自动配置,让Seata能够代理数据源。@EnableDiscoveryClient @EnableFeignClients @MapperScan(basePackages = {"cc.lisen.springcloud.alibaba.seata.dao"}) @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class SeataAccountServiceMain2003 { public static void main(String[] args) { SpringApplication.run(SeataAccountServiceMain2003.class, args); } }测试通过postman测试可以看到系统抛出了异常,然后我们查看以下数据库,可以看到数据没有发生任何变化。
2021年07月26日
1,067 阅读
0 评论
1 点赞
2021-07-26
Seata基础教程上-seata 1.4.2的安装及基于Nacos的配置
先吐槽一下,seata的文档真的是乱的一批。我们这里只介绍安装及基本使用过程。1.seata介绍Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。具体原理可以参考官网http://seata.io/zh-cn/docs/overview/what-is-seata.html。{message type="success" content="一定要注意版本问题,包括安装的Nacos版本、Seata版本、Spring Cloud版本、Spring Boot版本等等。"/}2.前置条件2.1安装JDK并配置环境变量安装JDK1.8及以上版本,并正确配置环境变量。2.2maven我这里用的是3.6.3,并配置阿里云仓库。2.3Git由于需要将Seata Server的配置文件导入Nacos,所以需要安装Git2.4安装NacosNacos 2.0.2版本,关于Nacos的安装,我们稍后会出一个专门的文章进行介绍。温馨提示 所以学习本篇文章之前,您至少应该改知道Nacos的安装以及在Spring Cloud中如何利用Nacos进行服务的注册与发现。Nacos默认端口为8848,由于我这里配置了集群,所以前端端口使用的是1111,大家在下面配置文件注意以下。3.seata安装我这里使用的seata是1.4.2(截止到目前最新的版本)。3.1.修改配置文件3.1.1.修改file.conf进入Seata的conf目录,找到file.conf,如下图修改以下内容## transaction log store, only used in seata-server store { ## store mode: file、db、redis mode = "db" #我们用数据库存储,改成db ## rsa decryption public key publicKey = "" ## file store property file { ## store location dir dir = "sessionStore" # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions maxBranchSessionSize = 16384 # globe session size , if exceeded throws exceptions maxGlobalSessionSize = 512 # file buffer size , if exceeded allocate new buffer fileWriteBufferCacheSize = 16384 # when recover batch read size sessionReloadReadSize = 100 # async, sync flushDiskMode = async } ## database store property db { ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc. datasource = "druid" ## mysql/oracle/postgresql/h2/oceanbase etc. dbType = "mysql" # 改成MySql driverClassName = "com.mysql.jdbc.Driver" ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param url = "jdbc:mysql://ip:3306/数据库名称?rewriteBatchedStatements=true" user = "数据库用户" password = "数据库密码" minConn = 5 maxConn = 100 globalTable = "global_table" branchTable = "branch_table" lockTable = "lock_table" queryLimit = 100 maxWait = 5000 } ## redis store property redis { ## redis mode: single、sentinel mode = "single" ## single mode property single { host = "127.0.0.1" port = "6379" } ## sentinel mode property sentinel { masterName = "" ## such as "10.28.235.65:26379,10.28.235.65:26380,10.28.235.65:26381" sentinelHosts = "" } password = "" database = "0" minConn = 1 maxConn = 10 maxTotal = 100 queryLimit = 100 } } 3.1.2.修改registry.conf进入Seata的conf目录,找到registry.conf,如下图我们这里用Nacos,所以主要是配置Nacos的信息,配置内容包括两部分,registry服务,将type从file改成nacos,将seata服务配置进nacos;config将type从file改成nacos,这样不需要每个项目都放file.conf修改内容如下:registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" #改成Nacos nacos { application = "seata-server" serverAddr = "127.0.0.1:1111" #Nacos地址,我这里集群用的1111端口,默认为8848端口 group = "SEATA_GROUP" #Nacos分组 namespace = "" username = "nacos" #Nacos用户名 password = "nacos" #Nacos密码 } eureka { serviceUrl = "http://localhost:8761/eureka" application = "default" weight = "1" } redis { serverAddr = "localhost:6379" db = 0 password = "" cluster = "default" timeout = 0 } zk { cluster = "default" serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } consul { cluster = "default" serverAddr = "127.0.0.1:8500" aclToken = "" } etcd3 { cluster = "default" serverAddr = "http://localhost:2379" } sofa { serverAddr = "127.0.0.1:9603" application = "default" region = "DEFAULT_ZONE" datacenter = "DefaultDataCenter" cluster = "default" group = "SEATA_GROUP" addressWaitTime = "3000" } file { name = "file.conf" } } config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" #改成Nacos nacos { serverAddr = "127.0.0.1:1111" #Nacos地址,我这里集群用的1111端口,默认为8848端口 namespace = "" group = "SEATA_GROUP" #Nacos分组 username = "nacos" #Nacos用户名 password = "nacos" #Nacos密码 # dataId = "" } consul { serverAddr = "127.0.0.1:8500" aclToken = "" } apollo { appId = "seata-server" ## apolloConfigService will cover apolloMeta apolloMeta = "http://192.168.1.204:8801" apolloConfigService = "http://192.168.1.204:8080" namespace = "application" apolloAccesskeySecret = "" cluster = "seata" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" nodePath = "/seata/seata.properties" } etcd3 { serverAddr = "http://localhost:2379" } file { name = "file.conf" } } 3.1.3.导入Seata相应的配置项到Nacos的配置中心(非注册中心)由于我这里注册中心跟配置中心用的一个,所以我其实导入的就是一个Nacos。3.1.3.1.创建导入脚本在conf文件夹下,创建nacos-config.sh,并将以下内容粘贴进去#!/usr/bin/env bash # Copyright 1999-2019 Seata.io Group. # # Licensed 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. while getopts ":h:p:g:t:u:w:" opt do case $opt in h) host=$OPTARG ;; p) port=$OPTARG ;; g) group=$OPTARG ;; t) tenant=$OPTARG ;; u) username=$OPTARG ;; w) password=$OPTARG ;; ?) echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] " exit 1 ;; esac done urlencode() { for ((i=0; i < ${#1}; i++)) do char="${1:$i:1}" case $char in [a-zA-Z0-9.~_-]) printf $char ;; *) printf '%%%02X' "'$char" ;; esac done } if [[ -z ${host} ]]; then host=localhost fi if [[ -z ${port} ]]; then port=8848 fi if [[ -z ${group} ]]; then group="SEATA_GROUP" fi if [[ -z ${tenant} ]]; then tenant="" fi if [[ -z ${username} ]]; then username="" fi if [[ -z ${password} ]]; then password="" fi nacosAddr=$host:$port contentType="content-type:application/json;charset=UTF-8" echo "set nacosAddr=$nacosAddr" echo "set group=$group" failCount=0 tempLog=$(mktemp -u) function addConfig() { curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$(urlencode $1)&group=$group&content=$(urlencode $2)&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/null if [[ -z $(cat "${tempLog}") ]]; then echo " Please check the cluster status. " exit 1 fi if [[ $(cat "${tempLog}") =~ "true" ]]; then echo "Set $1=$2 successfully " else echo "Set $1=$2 failure " (( failCount++ )) fi } count=0 for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do (( count++ )) key=${line%%=*} value=${line#*=} addConfig "${key}" "${value}" done echo "=========================================================================" echo " Complete initialization parameters, total-count:$count , failure-count:$failCount " echo "=========================================================================" if [[ ${failCount} -eq 0 ]]; then echo " Init nacos config finished, please start seata-server. " else echo " init nacos config fail. " fi3.1.3.2.创建配置文件在conf的上级目录,创建config.txt并粘贴以下内容transport.type=TCP transport.server=NIO transport.heartbeat=true transport.enableClientBatchSendRequest=true 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_tx_group=default #自定义,一定注意与spring cloud配置文件保持一致 service.default.grouplist=127.0.0.1:8091 #seata服务 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.tableMetaCheckerInterval=60000 client.rm.sqlParserType=druid client.rm.reportSuccessEnable=false client.rm.sagaBranchRegisterEnable=false client.rm.tccActionInterceptorOrder=-2147482648 client.tm.commitRetryCount=5 client.tm.rollbackRetryCount=5 client.tm.defaultGlobalTransactionTimeout=60000 client.tm.degradeCheck=false client.tm.degradeCheckAllowTimes=10 client.tm.degradeCheckPeriod=2000 client.tm.interceptorOrder=-2147482648 store.mode=db store.lock.mode=db store.session.mode=db store.publicKey= 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.jdbc.Driver store.db.url=jdbc:mysql://数据库IP:3306/seata?useUnicode=true&rewriteBatchedStatements=true store.db.user=数据库用户名 store.db.password=数据库密码 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.mode=single store.redis.single.host=127.0.0.1 store.redis.single.port=6379 store.redis.sentinel.masterName= store.redis.sentinel.sentinelHosts= store.redis.maxConn=10 store.redis.minConn=1 store.redis.maxTotal=100 store.redis.database=0 store.redis.password= 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 server.distributedLockExpireTime=10000 client.undo.dataValidation=true client.undo.logSerialization=jackson client.undo.onlyCareUpdateColumns=true server.undo.logSaveDays=7 server.undo.logDeletePeriod=86400000 client.undo.logTable=undo_log client.undo.compress.enable=true client.undo.compress.type=zip client.undo.compress.threshold=64k log.exceptionRate=100 transport.serialization=seata transport.compressor=none metrics.enabled=false metrics.registryType=compact metrics.exporterList=prometheus metrics.exporterPrometheusPort=9898上图一定要注意配置数据库信息及service.vgroupMapping.my_tx_group=default,这个后续在spring cloud项目的配置文件中会用到。3.1.3.3.导入配置文件打开git bash,进入到conf目录中,执行以下命令sh [nacos-config.sh文件路径] -h [nacos-ip地址] -p 8848 -g SEATA_GROUP[导入的组] -u [用户名] -w [密码] 执行完成后,查看我们Nacos配置中心中,配置文件是否已存在。3.1.4.创建相关的数据库(在回滚或提交前会将日志保存在数据库中,成功后会删除)3.1.3.1.创建seata数据库,并预置数据这个数据库就是我们上面配置文件中使用到的数据库,脚本如下-- -------------------------------- The script used when storeMode is 'db' -------------------------------- -- the table to store GlobalSession data CREATE TABLE IF NOT EXISTS `global_table` ( `xid` VARCHAR(128) NOT NULL, `transaction_id` BIGINT, `status` TINYINT NOT NULL, `application_id` VARCHAR(32), `transaction_service_group` VARCHAR(32), `transaction_name` VARCHAR(128), `timeout` INT, `begin_time` BIGINT, `application_data` VARCHAR(2000), `gmt_create` DATETIME, `gmt_modified` DATETIME, PRIMARY KEY (`xid`), KEY `idx_gmt_modified_status` (`gmt_modified`, `status`), KEY `idx_transaction_id` (`transaction_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; -- the table to store BranchSession data CREATE TABLE IF NOT EXISTS `branch_table` ( `branch_id` BIGINT NOT NULL, `xid` VARCHAR(128) NOT NULL, `transaction_id` BIGINT, `resource_group_id` VARCHAR(32), `resource_id` VARCHAR(256), `branch_type` VARCHAR(8), `status` TINYINT, `client_id` VARCHAR(64), `application_data` VARCHAR(2000), `gmt_create` DATETIME(6), `gmt_modified` DATETIME(6), PRIMARY KEY (`branch_id`), KEY `idx_xid` (`xid`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; -- the table to store lock data CREATE TABLE IF NOT EXISTS `lock_table` ( `row_key` VARCHAR(128) NOT NULL, `xid` VARCHAR(128), `transaction_id` BIGINT, `branch_id` BIGINT NOT NULL, `resource_id` VARCHAR(256), `table_name` VARCHAR(32), `pk` VARCHAR(36), `gmt_create` DATETIME, `gmt_modified` DATETIME, PRIMARY KEY (`row_key`), KEY `idx_branch_id` (`branch_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8;3.1.4.2.创建undo_log表注意:在业务数据库中创建undo_log,与上面的脚本不在一个数据库中。比如我有三个微服务,三个数据库,那么就需要在三个业务数据库中创建undo_log表-- 在业务数据库中创建undo_log(与上面的脚本不在一个数据库中) CREATE TABLE IF NOT EXISTS `undo_log` ( `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id', `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id', `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization', `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info', `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status', `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime', `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime', UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';4.运行seata运行Nacos这里不多介绍。运行seata进入seata的bin目录,执行./seata-server.bat,运行成功后,查看Nacos的服务列表能看到我们配置的seata即代表成功。
2021年07月26日
1,251 阅读
0 评论
0 点赞
2021-07-22
Spring Data Jpa 乐观锁
在数据库并发操作时,为了保证数据的正确性,我们会做一些并发处理,主要就是加锁。在加锁的选择上,常见有两种方式:悲观锁和乐观锁。悲观锁:简单的理解就是把需要的数据全部加锁,在事务提交之前,这些数据全部不可读取和修改。乐观锁:使用对单条数据进行版本校验和比较,来保证本次的更新是最新的,否则就失败,效率要高很多。实际工作中,乐观锁不止在数据库层面,其实我们在做分布式系统的时候,为了实现分布式系统的数据一致性,分布式事物的一种做法就是乐观锁。数据库操作举例说明悲观锁的做法select * from user where id = 1 for update; update user set name = '张三' where id = 1;通过使用for update给这条语句加锁,如果事务没有提交,其他任何读取和修改,都得排队等待。在代码中,我们加事务的java方法就会自然地形成了一个锁。乐观锁的做法select id,version from user where id = 1; update user set name = '张三',version=version+1 where id = 1 and version = 1;假设本次查询version=1,在更新操作时,带上这次查出来的Version,这样只有和我们上次版本一样的时候才会更新,就不会出现互相覆盖的问题,保证了数据的原子性。Jpa中乐观锁解决方案在没有@Version之前,我们都是自己手动维护这个version的,这样很有可能忘掉。或者是我们自己底层做框架,用AOP的思路做拦截底层维护这个Version的值。而Spring Data JPA的@Version就是通过AOP机制,帮我们动态维护这个Version,从而更优雅地实现乐观锁。实体上的version字段加上@Version注解即可。修改用户实体@Entity @Table(name = "sys_user") @Data @Slf4j @EntityListeners({UserAuditListener.class}) public class SysUser extends AbstractAuditable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; @JoinColumn(name = "dept_id", referencedColumnName = "dept_id") @ManyToOne(cascade = CascadeType.ALL) private SysDept sysDept; private String userName; private String nickName; private String userType; private String email; @Column(name = "phonenumber") private String phoneNumber; private String sex; private String avatar; @JsonIgnore private String password; @Enumerated(EnumType.STRING) private Status status; private String delFlag; private String loginIp; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.sql.Timestamp loginDate; private String remark; private Long recycleCompanyId; private Long medicalInstitutionId; private Long ethnicity; @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "sys_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")}) private Set<SysRole> sysRoles; @Version private Long version; }测试更新@GetMapping("/save") public SysUser save(){ Optional<SysUser> sysUserOptional = sysUserRepository.findById(100L); sysUserOptional.get().setNickName("哈哈"); return sysUserRepository.save(sysUserOptional.get()); }我们查看控制台输出信息,可以看到实际Sql中自动追加了version字段。同时我们查看数据库的version字段,值自动+1了
2021年07月22日
1,123 阅读
0 评论
0 点赞
2021-07-22
Spring Data Jpa Listener事件的扩展之自定义EntityListener
随着DDD的设计模式逐渐被大家认可和热捧。JPA通过Listener这种机制可以很好地实现事件分离、状体分离。假如,订单的状态变化。可能对我们来说比较重要,我们需要定一个类去监听订单状态变更,通知相应的逻辑代码各自去干各自的活。新增一个UserAuditListener类,在相应的操作上添加Callbacks注解@Slf4j public class UserAuditListener { @PostPersist private void postPersist(SysUser sysUser) { recordLog(sysUser, OperateType.CREATE); } @PostRemove private void postRemove(SysUser sysUser) { recordLog(sysUser, OperateType.REMOVE); } @PostUpdate private void postUpdate(SysUser sysUser) { recordLog(sysUser, OperateType.UPDATE); } @PostLoad public void postLoad(SysUser sysUser) { recordLog(sysUser, OperateType.LOAD); } /** * 记录审计日志 * * @param sysUser 用户实体 * @param operateType 操作类型 */ private void recordLog(SysUser sysUser, OperateType operateType) { log.info("{}执行了{}操作", sysUser, operateType.getType()); } } enum OperateType { CREATE("创建"), UPDATE("更新"), REMOVE("删除"), LOAD("查询"); private final String type; OperateType(String type) { this.type = type; } public String getType() { return this.type; } }修改实体,增加@EntityListeners注解@Entity @Table(name = "sys_user") @Data @Slf4j @EntityListeners({UserAuditListener.class}) public class SysUser extends AbstractAuditable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; @JoinColumn(name = "dept_id", referencedColumnName = "dept_id") @ManyToOne(cascade = CascadeType.ALL) private SysDept sysDept; private String userName; private String nickName; private String userType; private String email; @Column(name = "phonenumber") private String phoneNumber; private String sex; private String avatar; @JsonIgnore private String password; @Enumerated(EnumType.STRING) private Status status; private String delFlag; private String loginIp; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.sql.Timestamp loginDate; private String remark; private Long recycleCompanyId; private Long medicalInstitutionId; private Long ethnicity; @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "sys_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")}) private Set<SysRole> sysRoles; }测试这样,我们在增删改查方法调用时,就会执行我们对应的callback注解的方法比如我们插入用户@GetMapping("/save") public Long save(){ SysUser sysUser = new SysUser(); sysUser.setNickName("测试123321"); sysUser.setUserName("测试123321"); sysUser.setSex("0"); sysUserRepository.save(sysUser); return sysUser.getUserId(); }保存后,会自动调用postPersist方法
2021年07月22日
1,358 阅读
0 评论
1 点赞
2021-07-22
Spring Data Jpa扩展之Auditing
Auditing翻译过来是审计和审核。Spring的优秀之处在于帮我们想到了很多我们平时烦琐事情的解决方案,我们在实际的业务系统中,针对一张表的操作大部分是需要记录谁什么时间创建的,谁什么时间修改的,并且能让我们方便地记录操作日志。Spring Data JPA为我们提供了审计功能的架构实现,提供了4个注解专门解决这件事:@CreatedBy:创建人。@CreatedDate:创建时间。@LastModifiedBy:最后修改人。@LastModifiedDate:最后修改时间。增加公共虚拟类一般情况下,创建人、创建时间、最后修改人、最后修改时间四个字段都是统一的。所以,我们可以将其提取到公共的类中,然后所有的实体类继承这个虚拟类。@EntityListeners(AuditingEntityListener.class) @MappedSuperclass public abstract class AbstractAuditable { @CreatedBy private String createBy; @CreatedDate @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.sql.Timestamp createTime; @LastModifiedBy private String updateBy; @LastModifiedDate @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.sql.Timestamp updateTime; }必须添加@MappedSuperclass注解"修改实体,继承AbstractAuditable@Entity @Table(name = "sys_user") @Data @Slf4j public class SysUser extends AbstractAuditable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; @JoinColumn(name = "dept_id", referencedColumnName = "dept_id") @ManyToOne(cascade = CascadeType.ALL) private SysDept sysDept; private String userName; private String nickName; private String userType; private String email; @Column(name = "phonenumber") private String phoneNumber; private String sex; private String avatar; @JsonIgnore private String password; @Enumerated(EnumType.STRING) private Status status; private String delFlag; private String loginIp; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.sql.Timestamp loginDate; private String remark; private Long recycleCompanyId; private Long medicalInstitutionId; private Long ethnicity; @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "sys_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")}) private Set<SysRole> sysRoles; }实现AbstractAuditable接口实现AbstractAuditable接口,提供创建者、最后修改者信息,这里我们随便模拟了以下常量。public class MyAuditorAware implements AuditorAware<String> { /** * Returns the current auditor of the application. * * @return the current auditor. */ @Override public Optional<String> getCurrentAuditor() { return Optional.of("测试用户"); } }开启Auditing功能通过@EnableJpaAuditing注解开启JPA的Auditing功能,并且告诉应用AuditorAware的实现类是谁。@SpringBootApplication @EnableJpaRepositories(queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND) @EnableJpaAuditing public class Example1Application { public static void main(String[] args) { SpringApplication.run(Example1Application.class, args); } @Bean public AuditorAware<String> auditorAware(){ return new MyAuditorAware(); } }测试 @GetMapping("/save") public Long save(){ SysUser sysUser = new SysUser(); sysUser.setNickName("测试123321"); sysUser.setUserName("测试123321"); sysUser.setSex("0"); sysUserRepository.save(sysUser); return sysUser.getUserId(); }
2021年07月22日
1,291 阅读
0 评论
0 点赞
2021-07-22
Spring Data Jpa QueryByExampleExecutor及JpaSpecificationExecutor的用法
QueryByExampleExecutor可以通过实体进行简单的查询。比如我们查询用于昵称是超级开头的用户。@RestController @RequestMapping("/user") public class UserController { @Resource private SysUserRepository sysUserRepository; @GetMapping("/findAll") @Transactional public List<SysUser> findAll() { SysUser sysUser = new SysUser(); sysUser.setNickName("超级"); ExampleMatcher exampleMatcher = ExampleMatcher.matching() .withMatcher("nickName", ExampleMatcher.GenericPropertyMatchers.startsWith()) .withIgnorePaths("focus"); Example<SysUser> sysUserExample = Example.of(sysUser, exampleMatcher); return sysUserRepository.findAll(sysUserExample); } }其实跟MyBatis-Plus类似,功能比较简单,只能拼接and查询,一般使用不是很多。JpaSpecificationExecutor使用Specification的要点就是CriteriaBuilder,通过这个对象来创建条件,之后返回一个Predicate对象。这个对象中就有了相应的查询需求,我们同样可以定义多个Specification,之后通过Specifications对象将其连接起来。修改接口public interface SysUserRepository extends JpaRepository<SysUser, Long>, JpaSpecificationExecutor<SysUser> { }测试@RestController @RequestMapping("/user") public class UserController { @Resource private SysUserRepository sysUserRepository; @GetMapping("/findAll") @Transactional public List<SysUser> findAll() { return sysUserRepository.findAll((root, criteriaQuery, criteriaBuilder) -> { Predicate p1 = criteriaBuilder.like(root.get("nickName"), "%超级%"); Predicate p2 = criteriaBuilder.equal(root.get("userName"), "admin"); Predicate p3 = criteriaBuilder.equal(root.get("email"),"ry@163.com"); return criteriaBuilder.and(p1, p2); }); } }
2021年07月22日
1,246 阅读
0 评论
0 点赞
1
...
21
22
23
...
53