SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务
1.简介
“本文主要介绍SpringBoot2.1.5 + Dubbo 2.7.3 + Mybatis 3.4.2 + Nacos 1.1.3 +Seata 0.8.0整合来实现Dubbo分布式事务管理,使用Nacos 作为 Dubbo和Seata的注册中心和配置中心,使用 MySQL 数据库和 MyBatis来操作数据。
”
如果你还对SpringBoot
、Dubbo
、Nacos
、Seata
、Mybatis
不是很了解的话,这里我为大家整理个它们的官网网站,如下
-
SpringBoot:https://spring.io/projects/spring-boot
-
Dubbo:http://dubbo.apache.org/en-us/
-
Nacos:https://nacos.io/zh-cn/docs/quick-start.html
-
Seata:https://github.com/seata/seata/wiki/Home_Chinese
-
MyBatis:http://www.mybatis.org/mybatis-3/zh/index.html
在这里我们就不一个一个介绍它们是怎么使用和原理,详细请学习官方文档,在这里我将开始对它们进行整合,完成一个简单的案例,来让大家了解Seata
来实现Dubbo
分布式事务管理的基本流程。
2.环境准备
2.1 下载nacos并安装启动
nacos下载:https://github.com/alibaba/nacos/releases/tag/1.1.3
Nacos 快速入门:https://nacos.io/en-us/docs/quick-start.html
sh startup.sh -m standalone
1
在浏览器打开Nacos web 控制台:http://192.168.10.200:8848/nacos/index.html
输入nacos的账号和密码 分别为nacos:nacos
这是时候naocs 就正常启动了。
2.2 下载seata0.8.0 并安装启动
2.2.1 在 Seata Release 下载最新版的 Seata Server 并解压得到如下目录:
.
├──bin
├──conf
├──file_store
└──lib
12345
2.2.2 修改 conf/registry.conf 配置,
目前seata支持如下的file、nacos 、apollo、zk、consul的注册中心和配置中心。这里我们以nacos
为例。将 type 改为 nacos
registry {# file nacostype = "nacos"nacos {serverAddr = "192.168.10.200:8848"namespace = "public"cluster = "default"}file {name = "file.conf"}
}config {# file、nacos 、apollo、zk、consultype = "nacos"nacos {serverAddr = "192.168.10.200:8848"namespace = "public"cluster = "default"}file {name = "file.conf"}
}1234567891011121314151617181920212223242526272829
-
serverAddr = “192.168.10.200:8848” :nacos 的地址
-
namespace = “public” :nacos的命名空间默认为
public
-
cluster = “default” :集群设置未默认
default
注意:seata0.9.0之后,配置如下, 其中namespace = ""
registry {# file nacostype = "nacos"nacos {serverAddr = "192.168.10.200:8848"namespace = ""cluster = "default"}file {name = "file.conf"}
}config {# file、nacos 、apollo、zk、consultype = "nacos"nacos {serverAddr = "192.168.10.200:8848"namespace = ""}file {name = "file.conf"}
}
123456789101112131415161718192021222324252627
2.2.3 修改 conf/nacos-config.txt配置
注意:如果你的seata是1.1之后的版本请按照如下导入方式操作
-
下载https://github.com/seata/seata/blob/develop/script/config-center/目录下的
config.txt
文件放入到seata-server
目录下的conf中,可更改文件名为nacos-config.txt
。 -
下载https://github.com/seata/seata/tree/develop/script/config-center/nacos/目录下的nacos-config.py文件(window可用python命令执行,linux也可执行,前提先有安装python)或者nacos-config.sh文件(window下可放在git命令行执行,linux可执行文件)
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.thread-factory.boss-thread-prefix=NettyBoss
transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
transport.thread-factory.share-boss-worker=false
transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
transport.thread-factory.client-selector-thread-size=1
transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
transport.thread-factory.boss-thread-size=1
transport.thread-factory.worker-thread-size=8
transport.shutdown.wait=3
service.vgroup_mapping.order-service-seata-service-group=default
service.vgroup_mapping.account-service-seata-service-group=default
service.vgroup_mapping.storage-service-seata-service-group=default
service.vgroup_mapping.business-service-seata-service-group=default
service.enableDegrade=false
service.disable=false
service.max.commit.retry.timeout=-1
service.max.rollback.retry.timeout=-1
client.async.commit.buffer.limit=10000
client.lock.retry.internal=10
client.lock.retry.times=30
store.mode=db
store.file.dir=file_store/data
store.file.max-branch-session-size=16384
store.file.max-global-session-size=512
store.file.file-write-buffer-cache-size=16384
store.file.flush-disk-mode=async
store.file.session.reload.read_size=100
store.db.driver-class-name=com.mysql.jdbc.Driver
store.db.datasource=dbcp
store.db.db-type=mysql
store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true
store.db.user=lidong
store.db.password=cwj887766@@
store.db.min-conn=1
store.db.max-conn=3
store.db.global.table=global_table
store.db.branch.table=branch_table
store.db.query-limit=100
store.db.lock-table=lock_table
recovery.committing-retry-period=1000
recovery.asyn-committing-retry-period=1000
recovery.rollbacking-retry-period=1000
recovery.timeout-retry-period=1000
transaction.undo.data.validation=true
transaction.undo.log.serialization=jackson
transaction.undo.log.save.days=7
transaction.undo.log.delete.period=86400000
transaction.undo.log.table=undo_log
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registry-type=compact
metrics.exporter-list=prometheus
metrics.exporter-prometheus-port=9898
service.default.grouplist=127.0.0.1:8091
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
这里主要修改了如下几项:
-
store.mode :存储模式 默认file 这里我修改为db 模式 ,并且需要三个表
global_table
、branch_table
和lock_table
-
store.db.driver-class-name:默认没有,会报错。添加了
com.mysql.jdbc.Driver
-
store.db.datasource=dbcp :数据源 dbcp
-
store.db.db-type=mysql : 存储数据库的类型为
mysql
-
store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true : 修改为自己的数据库
url
、port
、数据库名称
-
store.db.user=lidong :数据库的账号
-
store.db.password=cwj887766@@ :数据库的密码
-
service.vgroup_mapping.order-service-seata-service-group=default
-
service.vgroup_mapping.account-service-seata-service-group=default
-
service.vgroup_mapping.storage-service-seata-service-group=default
-
service.vgroup_mapping.business-service-seata-service-group=default
也可以在 Nacos 配置页面添加,data-id 为 service.vgroup_mapping.${YOUR_SERVICE_NAME}-seata-service-group, group 为 SEATA_GROUP, 如果不添加该配置,启动后会提示no available server to connect to services-server
注意: 配置文件末尾有空行,需要删除,否则会提示失败,尽管实际上是成功的
db模式下的所需的三个表的数据库脚本位于seata\conf\db_store.sql
global_table
的表结构
CREATE TABLE `global_table` (`xid` varchar(128) NOT NULL,`transaction_id` bigint(20) DEFAULT NULL,`status` tinyint(4) NOT NULL,`application_id` varchar(64) DEFAULT NULL,`transaction_service_group` varchar(64) DEFAULT NULL,`transaction_name` varchar(64) DEFAULT NULL,`timeout` int(11) DEFAULT NULL,`begin_time` bigint(20) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`xid`),KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;1234567891011121314151617
branch_table
的表结构
CREATE TABLE `branch_table` (`branch_id` bigint(20) NOT NULL,`xid` varchar(128) NOT NULL,`transaction_id` bigint(20) DEFAULT NULL,`resource_group_id` varchar(32) DEFAULT NULL,`resource_id` varchar(256) DEFAULT NULL,`lock_key` varchar(128) DEFAULT NULL,`branch_type` varchar(8) DEFAULT NULL,`status` tinyint(4) DEFAULT NULL,`client_id` varchar(64) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;123456789101112131415161718
lock_table
的表结构
create table `lock_table` (`row_key` varchar(128) not null,`xid` varchar(96),`transaction_id` long ,`branch_id` long,`resource_id` varchar(256) ,`table_name` varchar(32) ,`pk` varchar(32) ,`gmt_create` datetime ,`gmt_modified` datetime,primary key(`row_key`)
);
123456789101112
2.2.4 将 Seata 配置添加到 Nacos 中
使用命令如下
cd conf
sh nacos-config.sh localhost
12
成功后会提示
init nacos config finished, please start seata-server
1
在 Nacos 管理页面应该可以看到有 59 个 Group 为SEATA_GROUP的配置
2.2.5 启动 Seata Server
使用db 模式启动
cd ..sh ./bin/seata-server.sh
12
这时候在 Nacos 的服务列表下面可以看到一个名为serverAddr的服务
3 案例分析
参考官网中用户购买商品的业务逻辑。整个业务逻辑由4个微服务提供支持:
-
库存服务:扣除给定商品的存储数量。
-
订单服务:根据购买请求创建订单。
-
帐户服务:借记用户帐户的余额。
-
业务服务:处理业务逻辑。
请求逻辑架构
3.1 github地址
springboot-dubbo-seata:https://github.com/lidong1665/springboot-dubbo-seata
-
samples-common :公共模块
-
samples-account :用户账号模块
-
samples-order :订单模块
-
samples-storage :库存模块
-
samples-business :业务模块
3.2 账户服务:AccountDubboService
/*** @Author: lidong* @Description 账户服务接口* @Date Created in 2019/9/5 16:37*/
public interface AccountDubboService {/*** 从账户扣钱*/ObjectResponse decreaseAccount(AccountDTO accountDTO);
}
123456789101112
3.3 订单服务:OrderDubboService
/*** @Author: lidong* @Description 订单服务接口* @Date Created in 2019/9/5 16:28*/
public interface OrderDubboService {/*** 创建订单*/ObjectResponse<OrderDTO> createOrder(OrderDTO orderDTO);
}
123456789101112
3.4 库存服务:StorageDubboService
/*** @Author: lidong* @Description 库存服务* @Date Created in 2019/9/5 16:22*/
public interface StorageDubboService {/*** 扣减库存*/ObjectResponse decreaseStorage(CommodityDTO commodityDTO);
}12345678910111213
3.5 业务服务:BusinessService
/*** @Author: lidong* @Description* @Date Created in 2019/9/5 17:17*/
public interface BusinessService {/*** 出处理业务服务* @param businessDTO* @return*/ObjectResponse handleBusiness(BusinessDTO businessDTO);
}
123456789101112131415
业务逻辑的具体实现主要体现在 订单服务的实现和业务服务的实现
订单服务的实现
@Service
public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements ITOrderService {@Reference(version = "1.0.0")private AccountDubboService accountDubboService;/*** 创建订单* @Param: OrderDTO 订单对象* @Return: OrderDTO 订单对象*/@Overridepublic ObjectResponse<OrderDTO> createOrder(OrderDTO orderDTO) {ObjectResponse<OrderDTO> response = new ObjectResponse<>();//扣减用户账户AccountDTO accountDTO = new AccountDTO();accountDTO.setUserId(orderDTO.getUserId());accountDTO.setAmount(orderDTO.getOrderAmount());ObjectResponse objectResponse = accountDubboService.decreaseAccount(accountDTO);//生成订单号orderDTO.setOrderNo(UUID.randomUUID().toString().replace("-",""));//生成订单TOrder tOrder = new TOrder();BeanUtils.copyProperties(orderDTO,tOrder);tOrder.setCount(orderDTO.getOrderCount());tOrder.setAmount(orderDTO.getOrderAmount().doubleValue());try {baseMapper.createOrder(tOrder);} catch (Exception e) {response.setStatus(RspStatusEnum.FAIL.getCode());response.setMessage(RspStatusEnum.FAIL.getMessage());return response;}if (objectResponse.getStatus() != 200) {response.setStatus(RspStatusEnum.FAIL.getCode());response.setMessage(RspStatusEnum.FAIL.getMessage());return response;}response.setStatus(RspStatusEnum.SUCCESS.getCode());response.setMessage(RspStatusEnum.SUCCESS.getMessage());return response;}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
整个业务的实现逻辑
@Service
@Slf4j
public class BusinessServiceImpl implements BusinessService{@Reference(version = "1.0.0")private StorageDubboService storageDubboService;@Reference(version = "1.0.0")private OrderDubboService orderDubboService;private boolean flag;/*** 处理业务逻辑* @Param:* @Return:*/@GlobalTransactional(timeoutMills = 300000, name = "dubbo-gts-seata-example")@Overridepublic ObjectResponse handleBusiness(BusinessDTO businessDTO) {log.info("开始全局事务,XID = " + RootContext.getXID());ObjectResponse<Object> objectResponse = new ObjectResponse<>();//1、扣减库存CommodityDTO commodityDTO = new CommodityDTO();commodityDTO.setCommodityCode(businessDTO.getCommodityCode());commodityDTO.setCount(businessDTO.getCount());ObjectResponse storageResponse = storageDubboService.decreaseStorage(commodityDTO);//2、创建订单OrderDTO orderDTO = new OrderDTO();orderDTO.setUserId(businessDTO.getUserId());orderDTO.setCommodityCode(businessDTO.getCommodityCode());orderDTO.setOrderCount(businessDTO.getCount());orderDTO.setOrderAmount(businessDTO.getAmount());ObjectResponse<OrderDTO> response = orderDubboService.createOrder(orderDTO);//打开注释测试事务发生异常后,全局回滚功能
// if (!flag) {
// throw new RuntimeException("测试抛异常后,分布式事务回滚!");
// }if (storageResponse.getStatus() != 200 || response.getStatus() != 200) {throw new DefaultException(RspStatusEnum.FAIL);}objectResponse.setStatus(RspStatusEnum.SUCCESS.getCode());objectResponse.setMessage(RspStatusEnum.SUCCESS.getMessage());objectResponse.setData(response.getData());return objectResponse;}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
3.6 使用seata的分布式事务解决方案处理dubbo的分布式事务
我们只需要在业务处理的方法handleBusiness
添加一个注解 @GlobalTransactional
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-gts-seata-example")@Overridepublic ObjectResponse handleBusiness(BusinessDTO businessDTO) {}
12345
-
timeoutMills
: 超时时间 -
name
:事务名称
3.7 准备数据库
注意: MySQL必须使用InnoDB engine
.
创建数据库 并导入数据库脚本
DROP DATABASE IF EXISTS seata;
CREATE DATABASE seata;
USE seata;DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) DEFAULT NULL,`amount` double(14,2) DEFAULT '0.00',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account` VALUES ('1', '1', '4000.00');-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (`id` int(11) NOT NULL AUTO_INCREMENT,`order_no` varchar(255) DEFAULT NULL,`user_id` varchar(255) DEFAULT NULL,`commodity_code` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT '0',`amount` double(14,2) DEFAULT '0.00',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_order
-- ------------------------------ ----------------------------
-- Table structure for t_storage
-- ----------------------------
DROP TABLE IF EXISTS `t_storage`;
CREATE TABLE `t_storage` (`id` int(11) NOT NULL AUTO_INCREMENT,`commodity_code` varchar(255) DEFAULT NULL,`name` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_storage
-- ----------------------------
INSERT INTO `t_storage` VALUES ('1', 'C201901140001', '水杯', '1000');-- ----------------------------
-- Table structure for undo_log
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of undo_log
-- ----------------------------
SET FOREIGN_KEY_CHECKS=1;
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
会看到如上的4个表
+-------------------------+
| Tables_in_seata |
+-------------------------+
| t_account |
| t_order |
| t_storage |
| undo_log |
+-------------------------+
12345678
这里为了简化我将这个三张表创建到一个库中,使用是三个数据源来实现。
3.8 我们以账号服务samples-account
为例 ,分析需要注意的配置项目
3.8.1 引入的依赖
<?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><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><artifactId>springboot-dubbo-seata</artifactId><packaging>pom</packaging><name>springboot-dubbo-seata</name><groupId>io.seata</groupId><version>1.0.0</version><description>samples-account</description》<properties><springboot.verison>2.1.5.RELEASE</springboot.verison><java.version>1.8</java.version><druid.version>1.1.10</druid.version><mybatis.version>1.3.2</mybatis.version><mybatis-plus.version>2.3</mybatis-plus.version><nacos.version>0.2.3</nacos.version><lombok.version>1.16.22</lombok.version><dubbo.version>2.7.3</dubbo.version><nacos-client.verison>1.1.3</nacos-client.verison><seata.version>0.8.0</seata.version><netty.version>4.1.32.Final</netty.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>${dubbo.version}</version><exclusions><exclusion><artifactId>spring</artifactId><groupId>org.springframework</groupId></exclusion></exclusions></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.version}</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-config-spring --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-config-spring</artifactId><version>${dubbo.version}</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId><version>${dubbo.version}</version></dependency><!-- https://mvnrepository.com/artifact/io.seata/seata-all --><dependency><groupId>io.seata</groupId><artifactId>seata-all</artifactId><version>${seata.version}</version></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>${nacos-client.verison}</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba.boot/nacos-config-spring-boot-starter --><dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>${nacos.version}</version><exclusions><exclusion><artifactId>nacos-client</artifactId><groupId>com.alibaba.nacos</groupId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>${netty.version}</version></dependency><dependency><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId><version>1.0.2</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-deploy-plugin</artifactId><configuration><skip>true</skip></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin></plugins></build>
</project>123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
注意:
-
seata-all
: 这个是seata 所需的主要依赖 -
dubbo-spring-boot-starter
: springboot dubbo的依赖
其他的就不一一介绍,其他的一目了然,就知道是干什么的。
3.8.2 application.properties配置
server.port=8102
spring.application.name=dubbo-account-example#====================================Dubbo配置===============================================
dubbo.application.id= dubbo-account-example
dubbo.application.name= dubbo-account-example
dubbo.protocol.id=dubbo
dubbo.protocol.name=dubbo
dubbo.registry.id=dubbo-account-example-registry
dubbo.registry.address=nacos://192.168.10.200:8848
dubbo.protocol.port=20880
dubbo.application.qosEnable=false
dubbo.config-center.address=nacos://192.168.10.200:8848
dubbo.metadata-report.address=nacos://192.168.10.200:8848#====================================mysql 配置============================================
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.10.200:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=lidong
spring.datasource.password=cwj887766@@#=====================================mybatis 配置======================================
mybatis.mapper-locations=classpath*:/mapper/*.xml12345678910111213141516171819202122232425
3.8.3 registry.conf 配置 (naocs的配置)
registry {# file nacostype = "nacos"nacos {serverAddr = "192.168.10.200"namespace = "public"cluster = "default"}file {name = "file.conf"}
}config {# file、nacos 、apollo、zk、consultype = "nacos"file {name = "file.conf"}nacos {serverAddr = "192.168.10.200"namespace = "public"cluster = "default"}
}1234567891011121314151617181920212223242526272829
3.8.5 SeataAutoConfig 配置
package io.seata.samples.integration.account.config;import com.alibaba.druid.pool.DruidDataSource;import io.seata.rm.datasource.DataSourceProxy;
import io.seata.spring.annotation.GlobalTransactionScanner;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;/*** @Author: llidong* @Description seata global configuration* @Date Created in 2019/9/05 10:28*/
@Configuration
public class SeataAutoConfig {/*** autowired datasource config*/@Autowiredprivate DataSourceProperties dataSourceProperties;/*** init durid datasource** @Return: druidDataSource datasource instance*/@Bean@Primarypublic DruidDataSource druidDataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setUrl(dataSourceProperties.getUrl());druidDataSource.setUsername(dataSourceProperties.getUsername());druidDataSource.setPassword(dataSourceProperties.getPassword());druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());druidDataSource.setInitialSize(0);druidDataSource.setMaxActive(180);druidDataSource.setMaxWait(60000);druidDataSource.setMinIdle(0);druidDataSource.setValidationQuery("Select 1 from DUAL");druidDataSource.setTestOnBorrow(false);druidDataSource.setTestOnReturn(false);druidDataSource.setTestWhileIdle(true);druidDataSource.setTimeBetweenEvictionRunsMillis(60000);druidDataSource.setMinEvictableIdleTimeMillis(25200000);druidDataSource.setRemoveAbandoned(true);druidDataSource.setRemoveAbandonedTimeout(1800);druidDataSource.setLogAbandoned(true);return druidDataSource;}/*** init datasource proxy* @Param: druidDataSource datasource bean instance* @Return: DataSourceProxy datasource proxy*/@Beanpublic DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource){return new DataSourceProxy(druidDataSource);}/*** init mybatis sqlSessionFactory* @Param: dataSourceProxy datasource proxy* @Return: DataSourceProxy datasource proxy*/@Beanpublic SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSourceProxy);factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*.xml"));return factoryBean.getObject();}/*** init global transaction scanner** @Return: GlobalTransactionScanner*/@Beanpublic GlobalTransactionScanner globalTransactionScanner(){return new GlobalTransactionScanner("account-gts-seata-example", "account-service-seata-service-group");}
}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
其中:
@Beanpublic GlobalTransactionScanner globalTransactionScanner(){return new GlobalTransactionScanner("account-gts-seata-example", "account-service-seata-service-group");}
1234
GlobalTransactionScanner
: 初始化全局的事务扫描器
/*** Instantiates a new Global transaction scanner.** @param applicationId the application id* @param txServiceGroup the default server group*/public GlobalTransactionScanner(String applicationId, String txServiceGroup) {this(applicationId, txServiceGroup, DEFAULT_MODE);}
123456789
-
applicationId :为应用id 这里我传入的是
account-gts-seata-example
-
txServiceGroup: 默认server的分组 这里我传入的是
account-service-seata-service-group
这个和我们前面在nacos 配置的是保存一致。 -
DEFAULT_MODE:默认的事务模式 为AT_MODE + MT_MODE
3.8.6 AccountExampleApplication 启动类的配置
package io.seata.samples.integration.account;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener;@SpringBootApplication(scanBasePackages = "io.seata.samples.integration.account")
@MapperScan({"io.seata.samples.integration.account.mapper"})
@EnableDubbo(scanBasePackages = "io.seata.samples.integration.account")
public class AccountExampleApplication {public static void main(String[] args) {SpringApplication.run(AccountExampleApplication.class, args);}}1234567891011121314151617181920
-
@EnableDubbo
等同于@DubboComponentScan
和@EnableDubboConfig
组合 -
@DubboComponentScan
扫描 classpaths 下类中添加了@Service
和@Reference
将自动注入到spring beans中。 -
@EnableDubboConfig 扫描的dubbo的外部化配置。
4 启动所有的sample模块
启动 samples-account
、samples-order
、samples-storage
、samples-business
并且在nocos的控制台查看注册情况: http://192.168.10.200:8848/nacos/#/serviceManagement
我们可以看到上面的服务都已经注册成功。
5 测试
5. 1 发送一个下单请求
使用postman 发送 :http://localhost:8104/business/dubbo/buy
参数:
{"userId":"1","commodityCode":"C201901140001","name":"fan","count":50,"amount":"100"
}
1234567
返回
{"status": 200,"message": "成功","data": null
}
12345
这时候控制台:
2019-09-05 12:17:34.097 INFO 21860 --- [nio-8104-exec-4] i.s.s.i.c.controller.BusinessController : 请求参数:BusinessDTO(userId=1, commodityCode=C201901140001, name=fan, count=50, amount=100)
2019-09-05 12:17:34.146 INFO 21860 --- [nio-8104-exec-4] i.seata.tm.api.DefaultGlobalTransaction : Begin new global transaction [192.168.10.200:8091:2021380638]
2019-09-05 12:17:34.150 INFO 21860 --- [nio-8104-exec-4] i.s.s.i.c.service.BusinessServiceImpl : 开始全局事务,XID = 192.168.10.200:8091:2021380638
2019-09-05 12:17:36.966 INFO 21860 --- [nio-8104-exec-4] i.seata.tm.api.DefaultGlobalTransaction : [192.168.10.200:8091:2021380638] commit status:Committed
1234
事务提交成功,
我们来看一下数据库数据变化
t_account
t_order
t_storage
数据没有问题。
5.2 测试回滚
我们samples-business
将BusinessServiceImpl
的handleBusiness2
下面的代码去掉注释
if (!flag) {throw new RuntimeException("测试抛异常后,分布式事务回滚!");
}
123
使用postman 发送 :http://localhost:8104/business/dubbo/buy2
.响应结果:
{"timestamp": "2019-09-05T04:29:34.178+0000","status": 500,"error": "Internal Server Error","message": "测试抛异常后,分布式事务回滚!","path": "/business/dubbo/buy"
}
1234567
控制台
2019-09-05 12:29:32.836 INFO 17264 --- [nio-8104-exec-2] i.s.s.i.c.controller.BusinessController : 请求参数:BusinessDTO(userId=1, commodityCode=C201901140001, name=fan, count=50, amount=100)
2019-09-05 12:29:32.843 INFO 17264 --- [nio-8104-exec-2] i.s.common.loader.EnhancedServiceLoader : load ContextCore[null] extension by class[io.seata.core.context.ThreadLocalContextCore]
2019-09-05 12:29:32.848 INFO 17264 --- [nio-8104-exec-2] i.s.common.loader.EnhancedServiceLoader : load TransactionManager[null] extension by class[io.seata.tm.DefaultTransactionManager]
2019-09-05 12:29:32.849 INFO 17264 --- [nio-8104-exec-2] io.seata.tm.TransactionManagerHolder : TransactionManager Singleton io.seata.tm.DefaultTransactionManager@461585ac
2019-09-05 12:29:32.859 INFO 17264 --- [nio-8104-exec-2] i.s.common.loader.EnhancedServiceLoader : load LoadBalance[null] extension by class[io.seata.discovery.loadbalance.RandomLoadBalance]
2019-09-05 12:29:32.893 INFO 17264 --- [nio-8104-exec-2] i.seata.tm.api.DefaultGlobalTransaction : Begin new global transaction [192.168.10.200:8091:2021380674]
2019-09-05 12:29:32.897 INFO 17264 --- [nio-8104-exec-2] i.s.s.i.c.service.BusinessServiceImpl : 开始全局事务,XID = 192.168.10.200:8091:2021380674
2019-09-05 12:29:34.143 INFO 17264 --- [nio-8104-exec-2] i.seata.tm.api.DefaultGlobalTransaction : [192.168.10.200:8091:2021380674] rollback status:Rollbacked
2019-09-05 12:29:34.158 ERROR 17264 --- [nio-8104-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 测试抛异常后,分布式事务回滚!] with root causejava.lang.RuntimeException: 测试抛异常后,分布式事务回滚!at io.seata.samples.integration.call.service.BusinessServiceImpl.handleBusiness(BusinessServiceImpl.java:60) ~[classes/:na]at io.seata.samples.integration.call.service.BusinessServiceImpl$$FastClassBySpringCGLIB$$2ab3d645.invoke(<generated>) ~[classes/:na]at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]at io.seata.spring.annotation.GlobalTransactionalInterceptor$1.execute(GlobalTransactionalInterceptor.java:104) ~[seata-all-0.8.0.jar:0.8.0]at io.seata.tm.api.TransactionalTemplate.execute(TransactionalTemplate.java:64) ~[seata-all-0.8.0.jar:0.8.0]at io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalTransaction(GlobalTransactionalInterceptor.java:101) ~[seata-all-0.8.0.jar:0.8.0]at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:76) ~[seata-all-0.8.0.jar:0.8.0]at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]at io.seata.samples.integration.call.service.BusinessServiceImpl$$EnhancerBySpringCGLIB$$cb43f7ab.handleBusiness(<generated>) ~[classes/:na]at io.seata.samples.integration.call.controller.BusinessController.handleBusiness(BusinessController.java:37) ~[classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_144]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_144]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_144]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747) [tomcat-embed-core-9.0.19.jar:9.0.19]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.19.jar:9.0.19]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.19.jar:9.0.19]at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
我们查看数据库数据,已经回滚,和上面的数据一致。
相关文章:

SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务
1.简介 “ 本文主要介绍SpringBoot2.1.5 Dubbo 2.7.3 Mybatis 3.4.2 Nacos 1.1.3 Seata 0.8.0整合来实现Dubbo分布式事务管理,使用Nacos 作为 Dubbo和Seata的注册中心和配置中心,使用 MySQL 数据库和 MyBatis来操作数据。 ” 如果你还对SpringBoot、Dubbo、Nacos…...

MongoDB使用
文档连接: link 创建表 不需要创建表的语句,当插入表的第一条语句时,会隐式的创建表。 增 插入一条 db.people.insertOne({ user_id: "bcd001", age: 45, status: "A" } )插入多条 db.collection.insertMany([ <document 1&g…...

C#文件安全管理解析
在实际的项目开发中,我们经常需要使用到文件的I/O操作,主要包含对文件的增改删查等操作,这些基本的操作我们都是很熟悉,但是较少的人去考虑文件的安全和操作的管理等方面,例如文件的访问权限管理,文件数据的…...

基于Dubbo分布式学校信息管理系统设计与实现
一、引言 1.1 课题背景 随着时代的发展与进步,计算机网络也随之日益完善,渐渐覆盖了我们生活的各个方面。在信息化和数字化的时代背景下,使用计算机管理学校信息来提升教育工作的质量和效率,是大势所趋,所以近年来,随着网络技术的不断发展,使用信息管理系统的学校越来…...

oracle面试问题和笔记整理
oracle面试笔记 ORACLE 面试问题-技术篇(2) 如何判断数据库的时区? 解答:SELECT DBTIMEZONE FROM DUAL; 解释GLOBAL_NAMES设为TRUE的用途 解答:GLOBAL_NAMES指明联接数据库的方式。如果这个参数设置为TRUE, 在建立数据库链接时就必须用相同的名字连结远程数据库 23。如何…...

Hadoop_Yarn实践 (三) => (Yarn的基础架构、原理、容量/公平调度器、Tool接口、Yarn常用命令、核心参数)
目录 Hadoop_HDFS、Hadoop_MapReduce、Hadoop_Yarn 实践 (三)一、Hadoop_HDFS二、Hadoop_MapReduce三、Hadoop_Yarn1、Yarn资源调度1.1、基础架构1.2、Yarn的工作调度机制(Job提交过程)1.3、Yarn 调度器和调度算法1.3.1、先进先出调度器(FIFO…...

postgresql 从应用角度看快照snapshot使用,事务隔离控制不再神密
专栏内容:postgresql内核源码分析 个人主页:我的主页 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 快照使用 快照是事务中使用,配合事务的隔离级别,体现出不同的可见性。…...

mysql(mariadb)读写分离部署
目录 一、原理 二、准备环境 三、部署mysql主从复制 1.五台服务器下载mariadb 2.修改master配置文件,重启数据库 3.登录mysql创建replication 4.从服务器登录验证 5.获得master服务器 DB的相关信息 6.备份master原有数据 7.修改slave1、slave2配置 8. 进入…...

ES-工作原理
前言 搜索引擎是对数据的检索,而数据总体分为两种:结构化数据和非结构化数据。而对于结构化数据,因为他们具有特定的结构,所以一般都是可以通过关系型数据库MySQL/oracle的二维表的方式存储和搜索,也可以建立索引。…...

C++小结(4)
C 字符串 C 提供了两种类型的字符串表示形式: C 风格字符串C 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言,并在 C 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字…...

Java框架之spring 的 messaging
写在前面 本文看下spring message相关的内容。 1:Message?Messaging? Message是消息的意思,是一个名词。而Messaging是一个动名词,是将消息发送出去的意思,因此,我们的消息系统是messaging s…...

linux使用grep命令查询nginx的进程情况时总是出现 grep --color=auto nginx
问题: 每次使用ps aux | grep 服务名 命令查询某个服务的进程时,总会出现一条grep --colorauto 服务名 例如: ps aux | grep nginx # 会出现图片中的情况解答: 这是因为grep 也是一条命令,它在输出时,会…...

FFmpeg音视频开发知识点(二)
系列文章目录 FFmpeg音视频开发知识点(一) 文章目录 系列文章目录前言一、AAC音频编码1. ffmpeg编译第三方的libfdk_aac2. S16重采样FLTP 二、AAC音频解码总结 前言 该篇讲解一下,音频编解码中的难点,以及开发过程中遇到问题&am…...

【Java可执行命令】(十)JAR文件签名工具 jarsigner:通过数字签名及验证保证代码信任与安全,深入解析 Java的 jarsigner命令~
Java可执行命令之jarsigner 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法3.1.1 可选参数:jarsigner -keystore < url>3.1.2 可选参数:jarsigner -storepass <口令>3.1.3 可选参数:jarsigner -keypass <口令>3.1.4 可选参…...

c#调用c++ dll,Release版本内存访问错误
最近遇到个比较经典的案例,在c#中调用yara进行文件检测,yara是c编写的一个非常强大库,github有个大佬用c#对其进行了封装,使其能在跨平台下,只需编译yara的so或dll就能直接跑。但总是在Release版本下时不时就崩溃&…...

内网安全:Cobalt Strike 与 MSF 联动( 会话 相互转移 )
内网安全:Cobalt Strike 与 MSF 联动( 会话 相互转移 ) 在渗透中,有时候 Cobalt Strike 会话可能会受限制,所以我们需要把 Cobalt Strike 会话转移到 MSF 上进行后面的渗透。也有的时候会话在 MSF 上,但是…...

性能测试讲解超详细Jmeter
目录 什么是性能 性能测试的目的 功能测试和性能测试 基准测试 负载测试 稳定性测试 压力测试 并发测试 总结 性能测试指标 响应时间 并发数 吞吐量 点击数 错误率 资源使用率 总结 性能测试流程 性能测试需求分析 性能测试计划和方案 编辑性能测试用例编辑 性…...

微服务 – Spring Cloud – Nacos 配置中心
微服务 – Spring Cloud – Nacos 配置中心 文章目录 微服务 – Spring Cloud – Nacos 配置中心打开nacos面板新建配置引入依赖配置文件启动类业务类打开nacos面板新建配置 Data ID: nacos-config-client-dev.yaml Group: DEV-CLOUD2023 config:info: config info lalalal …...

超细,设计一个“完美“的测试用例,用户登录模块实例...
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 好的测试用例一定…...

【C#】文件拖拽,获取文件路径
系列文章 【C#】编号生成器(定义单号规则、固定字符、流水号、业务单号) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器(开始日期、结束日期) 本文链接:h…...

SAP PI/PO初步了解 2023.07.03
SAP PI/PO 是SAP 提供的一种集成中间件解决方案,用于在组织内部或不同组织之间实现系统的无缝通信和数据交换。它使企业能够以统一高效的方式集成各种应用和系统,无论这些系统的技术平台或数据格式如何。 以下是关于SAP PI/PO的简要概述: 1…...

Java中生产者消费者模型
在Java中,生产者消费者模型是一种常见的多线程编程模型,用于解决生产者和消费者之间的数据交互问题。 简介 生产者(Producer)负责生成数据,并将数据放入共享的缓冲区(队列)中。消费者…...

测试Hyperledger Fabric环境
首先进入fabric-samples目录中的first-networked 子目录 cd fabric-samples/first-network 在first-network目录下有一个自动化脚本byfn.sh,可以使用-help参数查看相应的可 用命令,在命令提示符中输入如下命令: ./byfn.sh --help命令执行成功后&#…...

ClickHouse查询sql长度超超过最大限制
ClickHouse查询sql长度超超过最大限制 Max query size exceeded ClickHouse exception, message: Code: 62. DB::Exception: Syntax error: failed at position 262102 (‘fwm00ud6a3ynu0kaxr.ya0eyemkbzdvrxkhwgchccll’) (line 10406, col 17): fwm00ud6a3ynu0kaxr.ya0eyemk…...

【Axure教程】拖动调整行高列宽的表格
表格是在系统软件中非常常用的工具。表格通常由行和列组成,用于以结构化的方式显示和组织数据。它们在各种场景中都有广泛的应用,包括数据分析、数据录入、报表生成、项目管理和数据可视化等领域。 今天作者就教大家如何在Axure里制作一个能通过鼠标拖动…...

中间件-netty(1)
netty 前言篇 文章目录 一、IO基础篇1.概念1.1 阻塞(Block)和非阻塞(Non-Block)1.2 同步(Synchronization)和异步(Asynchronous)1.3 BIO 与 NIO 对比1.3.1 面向流与面向缓冲1.3.2 阻塞与非阻塞1.3.3 选择器的问世 2.NIO 和 BIO 如何影响应用程序的设计2.1 API调用2.2 数据处理2…...

【方法】想把PDF文档转换成PPT,如何操作?
很多小伙伴在工作中,会使用PDF或者PPT来展示内容。那如果需要把PDF转换成PPT,要如何操作呢? 我们知道,PPT转换成PDF很容易操作,只需通过PPT的【导出】选项,就可以直接转换成PDF;还可以通过“另…...

Linux--设置目录或文件的默认权限:umask权限掩码
目录起始权限是从777,普通文件起始权限从666 为何我们创建一个目录或文件,默认权限是你所看到的样子? 因为凡是在umask中出现的权限,都不应该在最终权限中出现! 最终权限起始权限&(~umask)…...

C++实现websocket单server单client全双工通信(基于boost!!!)
自身环境:ubuntu18.04gcc7.5.0boost1.7,3 环境配置 gcc或者g一般都有,这里主要介绍一下boost的配置方法 执行如下代码: wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.bz2 --no-check-cert…...

好用的网址5
搜番神器:https://trace.moe/ Online converter:Online converter - convert video, images, audio and documents for free 格式转换 GIF Explode:https://gif-explode.com/ SongDonkey:SongDonkey - AI Online Audio Split…...