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…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...
