SpringCloudAliBaba篇之Seata:分布式事务组件理论与实践

1、事务简介

事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中,一个事务由一组SQL语句组成,事务具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID原则。

  • 原子性(atomicity): 事务中的操作要么都发生,要么都不发生
  • 一致性(consistency): 事务从一个一致性的状态变到另一个一致性的状态,
  • 隔离性(isolation): 事务之间不能相互干扰、相互隔离,隔离又分为四个级别: 读未提交(read uncommitted), 读已提交(read committed,解决脏读)、可重复读(rpeatable read ,解决不可重复读)、串行化(serializable 解决幻读)
  • 持久性(durability): 持久性也称为永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变是永久的,接下来的操作或故障不应该对其有任何影响。

1.1、本地事务

@Translation

大多数场景下,我们的应用都只需要操作单一的数据库,这种情况的事务我们称之为本地事务(Local Transation)。本地事务的ACID特性是数据库直接提供支持。本地事务应用架构如下所示:

image

1.2、常见的分布式事务解决方案

  • seata阿里分布式事务框架
  • 消息队列
  • saga
  • XA

他们都有一个共同点,都是两阶段(2PC)。两阶段是指完成整个分布式事务,划分成两个步骤完成。

这四种常见的分布式事务解决方法,分别对应着分布式事务的四种模式:AT、TCC、Sage、XA

2、Seata是什么

seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)

2.1、Seata的三大角色

TC(Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚

TM(Transaction Manager) - 事务管理器

RM(Resource) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

其中,TC为单独部署的Server服务端,TM和RM为嵌入到应用中的Client客户端。

2.2、AT(auto transcation)模式

AT模式是一种无侵入的分布式事务解决方案

阿里的seata框架,实现了该模式

在AT模式下,用户只需关注自己的“业务SQL”,用户的“业务SQL”作为第一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作。

image

AT模式如何做到对业务的无侵入:

  • 一阶段

在一阶段中,Seata会拦截“业务SQL”,首先解析SQL语义,找到“业务SQL要更新的业务数据,在业务数据被更新前,将其保存成“before image",然后执行”业务SQL“更新业务数据,在业务数据更新之后,再将其保存成”after image“,最后生成行锁,以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

image

  • 二阶段提交

二阶段如果是提交的话,因为业务“SQL”在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁进行删掉,完成数据清理即可。

image

  • 二阶段回滚:

二阶段如果是回滚的话,Seata就需要一阶段已经执行的“业务SQL”,还原业务数据,回滚方式便是用“before image"还原业务数据;但在还原前要首先要校验脏写,对比数据库当前业务数据和after image,如果两份数据一致就说明没有脏写,可以还原数据,如果不一致就说明有脏写需要人工干预处理。

image

2.3、TCC模式

  • 侵入性强,并且得自己实现相关事务控制逻辑
  • 整个过程中基本没有锁,性能更强

TCC模式需要用户根据自己的业务场景实现Try,ConfirmCancel三个操作;事务发起方在一阶段执行try方式,在二阶段提交执行Contirm方法;二阶段回滚执行Cancel方法。

image

2.4、Saga模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

image

2.5、XA模式

前提

  • 支持XA 事务的数据库。
  • Java 应用,通过 JDBC 访问数据库。

整体机制

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

image

  • 执行阶段:
    • 可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
    • 持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
  • 完成阶段:
    • 分支提交:执行 XA 分支的 commit
    • 分支回滚:执行 XA 分支的 rollback

3、Seata快速开始

3.1、Seata Server(TC)环境搭建

Server端存储模式(store.mode)支持三种:

  • file : 单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高(默认)
  • db(5.7+) :高可用模式,全局事务会话信息通过db共享,相应性能差些
  • redis : Seata-Server 1.3及以上版本支持,性能较高,存在事务信息丢失风险;请提前配置当前场景的redis持久化配置

3.1.2、db+Nacos方式部署

资源下载地址: 【1.3.0版本windows为例】

https://github.com/seata/seata/releases

1、打开config/file.conf

2、修改mode=“db”

3、修改数据库连接信息(url,username,password)

4、创建数据库(seata)

5、下载相关需要的资源

image

解压完成后,我们只需要要这个script文件夹即可

image

将这个文件夹放入我们的steta目录(方便我们用里面的一些资源)

image

6、引入sql,script/server/db/mysql.sql

image

7、打开conf/registry.conf文件进行修改

registry部分:

image

config部分:

image

8、修改script/config-center/config.txt,为了等一下导入配置

image

注意点:

配置的事务分组,要与客户端配置的事务分组保持一致

image

  • 客户端properties配置:springcloud.alibaba.seata.tx-service-group=my_test_tx_troup
  • default需要跟客户端和registry.conf中registry中的cluster保持一致

事务分组:异地机房停电容错机制

my_test_tx_group可以自定义 比如(guangzhou,shanghai),对应的client也要配置

9、配置参数同步到Nacos

1、进入script/config-center/nacos

image

如果你的ip和端口都是默认的话,直接双击即可。否则可以使用下面的启动方式

sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 93d7e8bc-389c-45e1-99a4-1b14a3309d4a

参数说明:

-h: nacos地址

-p: nacos端口号

-g: 配置分组,默认为SEATA_GROUP

-t: Nacos命名空间ID字段,默认为空

在git bash里面执行命令即可

image

10、打开nacos进行查看,所有配置成功同步

image

11、启动seata

找到seata/bin/seata-server.bat双击启动即可

image

所有启动参数

参数全写作用备注
-h–host指定在注册中心注册的ip不指定时获取当前ip,外部访问部署建议指定
-p–port指定server启动的端口默认8091
-m–storeMode事务日志存储方式支持file,db,redis,默认为file,注意:redis需seata-server1.3版本及以上
-n–serverNode用户指定seata-server节点id如1,2,3默认为1
-e–seataEnv指定seata-server运行环境如dev,test,服务启动会使用registry-dev.conf这样的配置

例子:bin/seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e tset

启动集群方式:

bin/seata-server.sh -p 8091 -n 1
bin/seata-server.sh -p 8092 -n 2
bin/seata-server.sh -p 8093 -n 3

这时候我们的steata已经进来了

image

3.2、分布式事务代码搭建

3.2.1、创建两个数据库

  • 订单数据库
CREATE TABLE `order` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单id',`product_id` bigint NOT NULL COMMENT '商品id',`total_amount` int NOT NULL COMMENT '商品数量',`status` tinyint NOT NULL COMMENT '状态',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 库存数据库
CREATE TABLE `stock` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '库存id',`product_id` bigint NOT NULL COMMENT '商品id',`count` bigint NOT NULL COMMENT '库存数量',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

image

3.2.2、创建几个服务模块

  • seata父模块

pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud-alibaba</artifactId><groupId>com.lili</groupId><version>0.0.1-SNAPSHOT</version></parent><packaging>pom</packaging><modules><module>seata_order</module><module>seata_stock</module></modules><modelVersion>4.0.0</modelVersion><artifactId>seata</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!--web场景启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mybatisPlus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency></dependencies>
</project>
  • seata_order子模块

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>seata</artifactId><groupId>com.lili</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata_order</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!--nacos 服务  注册与发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--添加openfeign的依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>
</project>

yml文件:

server:port: 8888
# 服务名称
spring:application:name: order-seata-servercloud:nacos:discovery:server-addr: 101.34.254.160:8847username: nacospassword: nacosnamespace: publicdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_order?characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: root

启动类

@EnableFeignClients
@SpringBootApplication
public class SeataOrderApplication {public static void main(String[] args) {SpringApplication.run(SeataOrderApplication.class,args);}
}

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("ll_order")
public class Order implements Serializable {private static final long serialVersionUID = 1L;/*** 订单id*/@TableId(value = "id",type = IdType.AUTO)private Long id;/*** 商品id*/@TableField("product_id")private Long productId;/*** 商品数量*/@TableField("total_amount")private Integer totalAmount;/*** 状态*/@TableField("status")private Integer status;
}

mapper层

@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

service层接口

public interface OrderService extends IService<Order> {void addOrder();
}

service层实现类

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {@AutowiredStockFeignService stockFeignService;@AutowiredOrderMapper orderMapper;@Overridepublic void addOrder(){// 模拟添加订单信息Order order = new Order();order.setStatus(0);order.setProductId(10L);order.setTotalAmount(20);// 添加订单orderMapper.insert(order);// 减少库存stockFeignService.updateStock();}
}

feign下的调用库存接口

@FeignClient(value = "stock-seata-server",path = "/stock")
public interface StockFeignService {@RequestMapping("/updateStock")void updateStock();
}

controller层

@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredpublic OrderService orderService;@RequestMapping("/addOrder")public void addOrder() {orderService.addOrder();}
}

  • seata_stock子模块

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>seata</artifactId><groupId>com.lili</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata_stock</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!--nacos 服务  注册与发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--添加openfeign的依赖--><dependency> <groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>
</project>

yml文件:

server:port: 9999
# 服务名称
spring:application:name: stock-seata-servercloud:nacos:discovery:server-addr: 101.34.254.160:8847username: nacospassword: nacosnamespace: publicdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_stock?characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: root

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("ll_stock")
public class Stock implements Serializable {private static final long serialVersionUID = 1L;/*** 库存id*/@TableId(value = "id", type = IdType.AUTO)private Long id;/*** 商品id*/@TableField("product_id")private Long productId;/*** 库存数量*/@TableField("count")private Long count;
}

mapper层

@Mapper
public interface StockMapper extends BaseMapper<Stock> {
}

service层接口

public interface StockService extends IService<Stock> {void updateStock();
}

service层实现类

@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements StockService {@AutowiredStockMapper stockMapper;@Overridepublic void updateStock() {// 模拟修改数据Stock stock = new Stock();stock.setId(1L);stock.setCount(900L-20L);stockMapper.updateById(stock);}
}

controller层

@RestController
@RequestMapping("/stock")
public class StockController {@Autowiredpublic StockService stockService;@RequestMapping("/updateStock")public void updateStock(){stockService .updateStock();}          
}

3.3.3、使用@Translation注解测试

服务消费方

@Transactional(rollbackFor = Exception.class )
public void addOrder(){// 模拟添加订单信息Order order = new Order();order.setStatus(0);order.setProductId(10L);order.setTotalAmount(20);// 添加订单orderMapper.insert(order);// 更新库存stockFeignService.updateStock();// 测试异常int i= 1/0;
}

进行调用测试

java.lang.ArithmeticException: / by zero

控制台正常报错,我们来看看数据库

image

订单表成功回滚,但是库存表却已经被改变了

image

3.3.4、整合seata(@GlobalTransactional)

第一步,两个服务都需添加下列依赖

<!--seata依赖-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

第二步:各微服务对应数据库中添加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,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

第三步:

配置事务的分组,这个要与前面设置的分组相对应(两个服务都需要配置)

spring:cloud:alibaba:seata:tx-service-group: my_test_tx_group

配置seata的注册中心和配置中心(两个服务都需配置)

#配置seata的注册中心,告诉seata client怎么去访问seate server(TC)
seata:registry:type: nacosnacos:server-addr: 101.34.254.160:8847  #seate server所在的nacos服务地址application: seata-server #seate server 的服务名username: nacospassword: nacosgroup: SEATA_GROUP # seate server 所在的组,默认就是SEATA_GROUP,没有改可以不用配置config: # 配置中心type: nacosnacos:server-addr: 101.34.254.160:8847username: nacospassword: nacosgroup: SEATA_GROUP# 如果是默认空间则可以不用添加namespace: 93d7e8bc-389c-45e1-99a4-1b14a3309d4a

最后,方法上加上@GlobalTransaction注解,重新测试

@GlobalTransactional
public void addOrder(){// 模拟添加订单信息Order order = new Order();order.setStatus(0);order.setProductId(10L);order.setTotalAmount(20);// 添加订单orderMapper.insert(order);// 减少库存stockFeignService.updateStock();// 测试异常int i= 1/0;
}

运行保存后,发现我们的数据成功回滚,分布式事务到这里已经完全配置成功了。

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

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

相关文章

【AI提示词专栏】提示词思维导图帮助

提示词重要作用 提示词&#xff0c;就像是我们生活中的“小助手”或者“贴心小棉袄”&#xff0c;总是在关键时刻给我们提供帮助和指引。它们就像那些无处不在的小标签&#xff0c;时刻提醒我们该做什么、不该做什么&#xff0c;或者给我们一些有趣的启示。 比如&#xff0c;在…

视觉SLAM中的相机分类及用途

视觉SLAM&#xff08;Simultaneous Localization and Mapping&#xff09;算法主要用于机器人和自动导航系统中&#xff0c;用于同时进行定位和建立环境地图。这种算法依赖于相机来捕捉环境数据。根据视觉SLAM的具体需求和应用场景&#xff0c;可以使用不同类型的相机。以下是用…

HarmonyOS4.0从零开始的开发教程19HarmonyOS应用/元服务上架

HarmonyOS&#xff08;十七&#xff09;HarmonyOS应用/元服务上架 概述 当您开发、调试完HarmonyOS应用/元服务&#xff0c;就可以前往AppGallery Connect申请上架&#xff0c;华为审核通过后&#xff0c;用户即可在华为应用市场获取您的HarmonyOS应用/元服务。 HarmonyOS会…

HTML_CSS的基本选择器的使用及其作用范围和优先级

目录 ✨CSS的使用&#xff1a;行内样式内部样式外部样式 ✨CSS基本选择器&#xff1a;id选择器class选择器标签选择器 ✨优先级&#xff1a;选择器的优先级样式表的优先级 ✨CSS的使用&#xff1a; 根据定义CSS的位置不同&#xff0c;分为行内样式、内部样式和外部样式 行内样…

数据库中对时间的操作(mySql、Oracle、pgSql)

目录 mySql PGSQL oracle 两个日期年数差 月数差 天数差 小时差 加一年 加一月 加一天 加一小时 加一分钟 加一秒 mySql -- %Y-%m-%d %H:%i:%s 区分大小写 m d i s小写 -- 两个日期年数差 SELECT TIMESTAMPDIFF(YEAR, STR_TO_DATE(2000-12-12,%Y-%m-%d), STR…

美颜SDK技术对比,深入了解视频美颜SDK的工作机制

如何在实时视频中呈现更加自然、美丽的画面&#xff0c;而这正是美颜SDK技术发挥作用的领域之一。本文将对几种主流视频美颜SDK进行深入比较&#xff0c;以揭示它们的工作机制及各自的优劣之处。 随着科技的不断进步&#xff0c;美颜技术已经从简单的图片处理发展到了视频领域…

Pandas中级教程——数据合并与连接

Python Pandas 中级教程&#xff1a;数据合并与连接 Pandas 是一款强大的数据处理库&#xff0c;提供了丰富的功能来处理和分析数据。在实际数据分析中&#xff0c;我们常常需要将不同数据源的信息整合在一起。本篇博客将深入介绍 Pandas 中的数据合并与连接技术&#xff0c;帮…

AI绘画室内设计提示词大全(持续更新)

当你开始使用AI绘画进行室内设计&#xff08;interior design&#xff09;时&#xff0c;选择合适的提示词和关键概念对于成功构思和实现你的设计理念至关重要。以下是一些关于室内设计的提示词&#xff0c;涵盖了空间类型、设计风格、光线效果、布局规划、材料类型以及其他要求…

硬件基础-电容

电容 本质&#xff1a;电容两端电压不能激变&#xff0c;所以可以起到稳定电压作用。充放电。 电容量的大小: 想使电容容量大:①使用介电常数高的介质 ②增大极板间的面积 ③减小极板间的距离。 品牌 国外&#xff1a;村田 muRata、松下 PANASONIC、三星 SAMSUNG、太诱 TAI…

sql_lab靶场搭建以及存在的一些问题

sql_lab靶场搭建问题 首先检查小皮版本 把小皮改到5.3.29版本如果没有可以直接点击更多版本进行选择安装 当版本不对时则会暴出这种错误 SETTING UP THE DATABASE SCHEMA AND POPULATING DATA IN TABLES: Fatal error: Uncaught Error: Call to undefined function mysql_co…

React面试题:Component,Element,Instance之间有什么区别和联系?

回答思路&#xff1a;分别是什么-->不同点-->相同点 Component&#xff08;组件&#xff09;&#xff1a;一个组件可以通过多种方式声明&#xff0c;可以是带一个render&#xff08;&#xff09;方法的类&#xff0c;也可以是一个函数&#xff0c;这两种情况下&#xff…

【QT】QTreeWidget控件的使用

目录 1.概述 2.QTreeWidget控件功能接口 2.1 构造函数 2.2 添加和访问顶级条目 2.3 条目访问函数 2.4 当前条目的操作 2.5 条目查找和排序 2.6 条目显示和运行时条目编辑 2.7 信号 2.8 槽函数 2.9 基类 QTreeView 的函数 2.10 树头条目 2.11选中行为和选中模式 3…

2018年第七届数学建模国际赛小美赛A题空中加油飞行计划解题全过程文档及程序

2018年第七届数学建模国际赛小美赛 A题 空中加油飞行计划 原题再现&#xff1a; 太平洋中部一个小岛上的居民被自然灾害困住。救援人员需要派遣一架轻型飞机运送少量急救药品到岛上&#xff0c;并运送一名重伤者到医疗基地求救。岛上有一个无人值守的简易机场&#xff0c;可以…

50ms时延工业相机

华睿工业相机A3504CG000 参数配置&#xff1a; 相机端到端理论时延&#xff1a;80ms 厂家同步信息&#xff0c;此款设备帧率上线23fps&#xff0c;单帧时延&#xff1a;43.48ms&#xff0c;按照一图缓存加上传输显示的话&#xff0c;厂家预估时延在&#xff1a;80ms 厂家还有…

基于Docker Compose的容器编排技术

1.1 介绍一下 Docker 建议我们每⼀个容器中只运⾏⼀个服务&#xff0c;因为 Docker 容器本身占⽤资源极少&#xff0c;所以最好是 将每个服务单独的分割开来但是这样我们⼜⾯临了⼀个问题&#xff1f; 如果我需要同时部署好多个服务&#xff0c;难道要每个服务单独写 Dockerf…

深入了解Linux信号:作用、产生、捕捉和阻塞

这里写目录标题 引言1. 信号的基本概念1.1 信号的分类和编号&#xff1a;1.2 查看信号默认处理动作1.3 信号的作用1.4 信号的产生 2. 常见信号及其作用示例 3. 信号捕捉和处理3.1 信号捕捉函数3.2 sigaction 函数示例 4. 信号阻塞示例 结语 引言 Linux操作系统中&#xff0c;信…

EM(Expectation-Maximum)算法

EM算法 简介 EM算法的核心分为两步 E步&#xff08;Expection-Step&#xff09;M步&#xff08;Maximization-Step&#xff09; 因为在最大化过程中存在两个参量 r , θ r,\theta r,θ&#xff0c;其中若知道 r r r&#xff0c;则知道 θ \theta θ&#xff1b;若知道 θ \…

mybatis一级缓存二级缓存和redis的区别

今天读到关于mybatis一级缓存、二级缓存的知识&#xff0c;然后看了一下mybatis一级缓存、二级缓存的应用场景&#xff0c;当时就感觉和redis很像&#xff0c;于是就查看了一下它们两个的区别。 Redis 和 MyBatis 一级缓存二级缓存的主要区别在于缓存的数据结构和存储方式上。…

机器学习之线性回归(Linear Regression)

概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…

java常用正则表达式验证方法

1、正则表达式来验证验证11位数字格式的中国大陆电话号码 public boolean validatePhoneNumber(String phoneNumber) {String regex "^1[3-9]\\d{9}$";return phoneNumber.matches(regex); }正则表达式“^1[3-9]\d{9}”用于匹配11位数字格式的中国大陆电话号码。其…