当前位置: 首页 > news >正文

Spring 多数据源搭建

目录

前言

正文 

1.Druid 介绍和使用 

2.其他多数据源解决方案 

总结


前言

对于复杂的业务和项目,可能在一个单体项目中存在需要连接多个数据库的情况。这时,就会使用到多数据源,实际中遇到的可能性比较大。


正文 

如果一个项目中需要连接 db1 ,同时一部分业务需要获取 db2 中的数据,则需要连接第二个数据源。这里一个数据源对应一个数据库,这两个数据库可能是部署在同一台服务器上,也可能不在同一台服务器上,通过配置 jdbc-url 来区别。

在配置上需要配置不同的 datasource 才能实现不同的数据源连接。

1.Druid 介绍和使用 

Druid 是阿里旗下开源的数据库连接池,提供强大的监控和扩展功能,包括数据库性能健康,获取 SQL 日志的能力。除此之外,也可以和 MyBaties 配合用于多数据源搭建。 

pom.xml依赖如下

        <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.23</version></dependency>

为了测试多数据源,创建一个主库 test_spring_master,一个从库 test_spring_slave,创建 SQL 如下:

create database test_spring_master default character set utf8;
create database test_spring_slave default character set utf8;

配置文件内容如下:

spring:datasource:master: #主数据元username: masterpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/test_spring_master?useTimezone=true&serverTimezone=UTCinitialSize: 5minIdle: 5maxActive: 20slave: #第二个数据源username: slavepassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/test_spring_slave?useTimezone=true&serverTimezone=UTCinitialSize: 5minIdle: 5maxActive: 20

针对两个数据源配置,需要编写两个配置类,一个是主数据源配置类,另一个是从数据源配置类,分别命名为 MasterDataSourceConfig 和 SlaveDataSourceConfig,代码如下: 

package org.example.config;import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;@Configuration
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE_NAME, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {//定位到包类路径static final String PACKAGE_NAME = "org.example.mapper.master";//设置 mapper.xml位置。//不存在 *.xml 这种模糊匹配,必须准确的名称static final String MAPPER_LOCATION="classpath:org/example/mapper/master/MySinger.xml";@Value("${spring.datasource.master.jdbc-url}")private String url;@Value("${spring.datasource.master.username}")private String user;@Value("${spring.datasource.master.password}")private String password;@Value("${spring.datasource.master.driver-class-name}")private String driverClass;/*** 获得主数据源* @return*/@Bean(name = "masterDataSource")public DataSource masterDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driverClass);//设置驱动dataSource.setUrl(url);dataSource.setUsername(user);dataSource.setPassword(password);return dataSource;}/*** 将 masterDataSource 注入到 masterTransactionManger* @return 管理数据库实物*/@Bean(name = "masterTransactionManger")public DataSourceTransactionManager masterTransactionManger(){//使用了 @Bean,则可以直接依赖注入进去return new DataSourceTransactionManager(masterDataSource());}@Bean(name = "masterSqlSessionFactory")@Primary //如果有多个相同类型的Bean 优先使用本Beanpublic SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource){final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(masterDataSource);sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResource(MasterDataSourceConfig.MAPPER_LOCATION));try {return sessionFactory.getObject();} catch (Exception e) {e.printStackTrace();}return null;}}

补充: 

  • @MapperScan 注解用于指定需要扫描的 Mapper 接口所在的包名,它通常与 @Configuration 注解一起使用,表示该注解所标注的类是一个配置类。basePackages 属性用于指定需要扫描的包名,多个包名可以用逗号隔开。例如,@MapperScan(basePackages = "com.example.mapper") 表示需要扫描 com.example.mapper 包以及其子包中的 Mapper 接口。
  • 此外,@MapperScan 注解还有一个 sqlSessionFactoryRef 属性,用于指定使用的 SqlSessionFactory 的名称,即在 Spring IoC 容器中定义的 SqlSessionFactory Bean 的名称。在多个数据源的情况下,可以通过该属性为不同的 Mapper 接口指定不同的 SqlSessionFactory,以使用不同的数据源。
  • 也就是说,@MapperScan 注解将指定包下的 MyBatis Mapper 接口与 SqlSessionFactory 关联起来。为了让 @MapperScan 注解知道要关联哪个 SqlSessionFactory 实例,需要通过 sqlSessionFactoryRef 属性指定 SqlSessionFactory 的 Bean 名称。

可以看到  masterSqlSessionFactory 方法上有 @Primary 注解,说明这时主库。而从数据源配置类和主数据源配置类比较类似,唯一不同就是一些参数和注解不同。

package org.example.config;import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
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;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;@Configuration
@MapperScan(basePackages = SlaveDataSourceConfig.PACKAGE_NAME, sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {//定位到包类路径static final String PACKAGE_NAME = "org.example.mapper.slave";//设置 mapper.xml位置。static final String MAPPER_LOCATION="classpath:org/example/mapper/slave/MyStore.xml";@Value("${spring.datasource.slave.jdbc-url}")private String url;@Value("${spring.datasource.slave.username}")private String user;@Value("${spring.datasource.slave.password}")private String password;@Value("${spring.datasource.slave.driver-class-name}")private String driverClass;/*** 获得主数据源* @return*/@Bean(name = "slaveDataSource")public DataSource slaveDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driverClass);//设置驱动dataSource.setUrl(url);dataSource.setUsername(user);dataSource.setPassword(password);return dataSource;}/*** 将 masterDataSource 注入到 masterTransactionManger* @return 管理数据库实物*/@Bean(name = "slaveTransactionManager")public DataSourceTransactionManager slaveTransactionManager(){//使用了 @Bean,则可以直接依赖注入进去return new DataSourceTransactionManager(slaveDataSource());}@Bean(name = "slaveSqlSessionFactory")public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(slaveDataSource);sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResource(SlaveDataSourceConfig.MAPPER_LOCATION));return sessionFactory.getObject();}}

为了进一步实验,需要在两个库中分别创建表,于是主库创建 m_singers 歌手表,在从数据库中创建 m_stores 商店表。

use test_spring_master;
create table `m_singers`(`id` int(11) unsigned not null auto_increment comment '歌手主键',`name` varchar(80) not null comment '歌手名',`age` int(3) default null comment '年龄',primary key (`id`)
)engine InnoDB default character set=utf8;
use test_spring_slave;
create table `m_stores`(`id` int(11) unsigned not null  auto_increment comment '主键',`name` varchar(100) NOT NULL  comment '店名',`space` int(6) not null  comment '单位平方米',`description` varchar(300) not null comment '简介',primary key (`id`)
)engine InnoDB DEFAULT character set=utf8;

创建用户并授予权限

create  user 'master'@'localhost' identified by'123456';
show grants for 'master'@'localhost';
create  user 'slave'@'localhost' identified by'123456';
GRANT ALL PRIVILEGES ON test_spring_slave.m_stores TO 'slave'@'localhost';
GRANT ALL PRIVILEGES ON test_spring_master.m_singers TO 'master'@'localhost';

 继续分别创建对应的实体类 

MyStore.java

package org.example.entity;import lombok.Data;import java.io.Serializable;@Data
public class MyStore implements Serializable {// 主键private Integer id;// 名称private String name;// 地区private int space;// 描述private String description;
}

MySinger.java 

package org.example.entity;import lombok.Data;import java.io.Serializable;@Data
public class MySinger implements Serializable {private Integer id;private String name;private int age;
}

对应的 Dao 文件:

MyStore。 

package org.example.mapper.slave;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.entity.MyStore;@Mapper
public interface MyStoreDao {int insert(MyStore record);int updateByPrimaryKey(MyStore record);MyStore findByName(@Param("name") String name);
}

MySinger。 

package org.example.mapper.master;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.entity.MySinger;@Mapper
public interface MySingerDao {int deleteByPrimaryKey(Integer id);int insert(MySinger record);int insertSelective(MySinger record);MySinger selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(MySinger record);int updateByPrimaryKey(MySinger record);MySinger findByName(@Param("name") String name);
}

剩下的 controller,service 部分基本就是一般流程了,就不继续向下写了。 最后自己进行测试:

完成 。

2.其他多数据源解决方案 

其他解决方案也很多,如使用多个 Bean、自实现动态 DataSource 等,其中有一种方法非常简单高效 ,就是使用第三方的依赖包,动态加载不同的数据源,推荐使用 dynamic-datasource-spring-boot-starter。

dynamic-datasource-spring-boot-starter 是国内开发者维护的多数据源解决方案插件被作者称为一个基于 springboot 的快速继承多数据源的启动器。它的优点主要有支持数据源分组,适用于多种场景,纯粹多库、读写分离、一主多从混合模式。

POM.xml依赖

        <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.1</version></dependency>

数据源配置

spring:datasource:dynamic:primary: master #设置默认的数据源或者数据数组,默认只即为 masterstrict: false #设置严格模式,默认false不启动。启动后在未匹配到指定数据源时会抛出异常,不启动则使用默认数据源。datasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver #3.2.0开始支持 SPI 可省略此配置slave_1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverslave_2:url: ENC(xxxxx) #内置加密,使用详情请看文档。username: ENC(xxxxx)password: ENC(xxxxx)driver-class-name: com.mysql.cj.jdbc.Driverscherma: db/schema.sql #配置生效,自动初始化表格data: db/data.sql #配置生效,自动初始化数据continue-on-error: true #默认true ,初始化失败是否separator: "," #sql 默认分隔符#这些配置会配置一个默认库 master, 一个组 slave 下有两个子库 slave_1, slave_2

配置解释:

在这段配置中:

spring.datasource.dynamic 是 dynamic-datasource-spring-boot-starter 的配置前缀。

  • primary: master 设置主数据源为 “master”。

  • strict: false 为非严格模式。如果请求的数据源不存在,系统会自动回退到主数据源,而不是抛出异常。

  • datasource: 下面列出了所有的数据源,每一个数据源都有一个名字(在这个例子中是 master, slave_1, slave_2),和对应的数据源详情(url, username, password, driver-class-name)。

每个具体的数据源(比如 “master”)下:

  • url: 数据库的 JDBC URL。

  • username: 数据库用户名。

  • password: 数据库密码。ENC(xxx) 是一个加密格式,能够保护你的敏感信息不被明文展示。

  • driver-class-name: JDBC 驱动类型。如果你依赖的版本在3.2.0以上,驱动可以被自动识别,这个配置也可以省略。

scherma: db/schema.sql 和 data: db/data.sql 是你自定义的SQL语句文件。在 Spring Boot 中可以通过这种方式定义 SQL 文件的路径,然后在应用启动的时候自动执行这些 SQL 文件。

强调一下,这只是个示例,你需要根据具体的数据库信息(如类型、地址、端口、用户名、密码等)去做相应的调整和修改。例如,替换 xx.xx.xx.xx 为实际的数据库服务器地址,并且替换 username 和 password 为正确的数据库访问凭证等。

最后使用 @DS 注解,采取就近原则,方法上的注解优先于类上的注解,代码如下 : 

package org.example.service;import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;import java.util.List;@Service
@DS("slave")
public class UserServiceImpl implements UserService{@Autowiredprivate JdbcTemplate jdbcTemplate;public List selectAll(){return jdbcTemplate.queryForList("select * from user");}@Override@DS("slave_1")public List selectByCondition(){return jdbcTemplate.queryForList("select * from user where age > 10");}}


总结

多数据源搭建提供了灵活性、性能优化、隔离性和安全性方面的优势。它使应用程序能够更好地适应不同的需求,并在处理数据时提供更好的性能和可扩展性。

相关文章:

Spring 多数据源搭建

目录 前言 正文 1.Druid 介绍和使用 2.其他多数据源解决方案 总结 前言 对于复杂的业务和项目&#xff0c;可能在一个单体项目中存在需要连接多个数据库的情况。这时&#xff0c;就会使用到多数据源&#xff0c;实际中遇到的可能性比较大。 正文 如果一个项目中需要连…...

【二分查找】LeetCode1970:你能穿过矩阵的最后一天

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个下标从 1 开始的二进制矩阵&#xff0c;其中 0 表示陆地&#xff0c;1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。 一开始在第 0 …...

利用python连接MySQL数据库并执行相关sql操作

一、新建MySQL数据库 1.启动MySQL服务 打开phpstudy&#xff0c;开启MySQL服务。如果开启失败的话&#xff0c;可以打开任务管理器&#xff0c;把正在运行的mysqld服务的进程进行关闭&#xff0c;再次打开MySQL服务即可启动。 2.新建MySQL数据库 选择数据库&#xff0c;点击…...

jenkins配置

branch: "dev" 切换分支 $WORKSPACE&#xff1a; /var/lib/jenkins/workspace/jenkins任务名 dest_passwd服务器密码 变量 sudo sshpass -p $dest_passwd ssh root192.168.211.319 -tt rm -rf /data/patent/*&#xff1a;删除文件/data/patent/* sudo sshpa…...

LeNet对MNIST 数据集中的图像进行分类--keras实现

我们将训练一个卷积神经网络来对 MNIST 数据库中的图像进行分类&#xff0c;可以与前面所提到的CNN实现对比CNN对 MNIST 数据库中的图像进行分类-CSDN博客 加载 MNIST 数据库 MNIST 是机器学习领域最著名的数据集之一。 它有 70,000 张手写数字图像 - 下载非常简单 - 图像尺…...

Django的回顾的第4天

1.模型层 1.1简介 你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说&#xff0c;HTML被直接硬编码在 Python代码之中。 def current_datetime(request):now datetime.datetime.now()html "<html><body>It is now %s.</body><…...

点云从入门到精通技术详解100篇-基于三维点云的工件曲面轮廓检测与机器人打磨轨迹规划(中)

目录 2.2.2 散乱点云滤波去噪 2.2.3 海量点云数据压缩 2.3 点云采集与预处理实验...

Mapper文件夹在resource目录下但是网页报错找不到productMapper.xml文件的解决

报错如下&#xff1a; 我的Mapper文件夹在resourse目录下但是网页报错找不到productMapper.xml。 结构如下&#xff1a;代码如下&#xff1a;<mappers><mapper resource"com/dhu/mapper/productMapper.xml" /> </mappers> 这段代码是在mybatis-co…...

22.Oracle中的临时表空间

Oracle中的临时表空间 一、临时表空间概述1、什么是临时表空间2、临时表空间的作用 二、临时表空间相关语法三、具体使用案例1、具体使用场景示例2、具体使用场景代码示例 点击此处跳转下一节&#xff1a;23.Oracle11g的UNDO表空间点击此处跳转上一节&#xff1a;21.Oracle的程…...

附录A 指令集基本原理

1. 引言 本书主要关注指令集体系结构4个主题&#xff1a; 1. 提出对指令集进行分类的方法&#xff0c;并对各种方法的优缺点进行定性评估&#xff1b; 2. 提出并分析一些在很大程度上独立于特定指令集的指令集评估数据。 3. 讨论语言与编译器议题以及…...

Unittest单元测试之unittest用例执行顺序

unittest用例执行顺序 当在一个测试类或多个测试模块下&#xff0c;用例数量较多时&#xff0c;unittest在执行用例 &#xff08;test_xxx&#xff09;时&#xff0c;并不是按从上到下的顺序执行&#xff0c;有特定的顺序。 unittest框架默认根据ACSII码的顺序加载测试用例&a…...

海云安谢朝海:开发安全领域大模型新实践 人工智能助力高效安全左移

2023年11月29日&#xff0c;2023中国&#xff08;深圳&#xff09;金融科技大会成功举行&#xff0c;该会议是深圳连续举办的第七届金融科技主题年度会议&#xff0c;也是2023深圳国际金融科技节重要活动之一。做好金融工作&#xff0c;需要兼顾创新与安全&#xff0c;当智能体…...

Postman接口测试工具完整教程

前言 作为软件开发过程中一个非常重要的环节&#xff0c;软件测试越来越成为软件开发商和用户关注的焦点。完善的测试是软件质量的保证&#xff0c;因此软件测试就成了一项重要而艰巨的工作。要做好这项工作当然也绝非易事。 第一部分&#xff1a;基础篇 postman:4.5.1 1.安…...

Android 滑动按钮(开关) SwitchCompat 自定义风格

原生的SwitchCompat控件如下图&#xff0c;不说不堪入目&#xff0c;也算是不敢恭维了。开个玩笑... 所以我们就需要对SwitchCompat进行自定义风格&#xff0c;效果如下图 代码如下 <androidx.appcompat.widget.SwitchCompatandroid:id"id/switch_compat"android:…...

前端面试灵魂提问-计网(2)

1、websocket 为什么全双工? 1.1 WebSocket是什么 WebSocket 是一种通信协议&#xff0c;它在客户端和服务器之间建立持久的全双工连接。全双工意味着数据可以双向流动&#xff0c;即客户端可以向服务器发送消息&#xff0c;服务器也可以向客户端发送消息&#xff0c;而无需…...

Git修改远程仓库名称

1、先直接在远程点仓库名&#xff0c;然后左侧菜单栏找settings-general&#xff0c;然后直接修改工程名&#xff0c;保存即可。 2、还是在settings-general下&#xff0c;下拉找到Advanced点击Expand展开&#xff0c;然后下拉到最底部 在Change path里填入新的项目名称&#x…...

kafka 集群 ZooKeeper 模式搭建

Apache Kafka是一个开源分布式事件流平台&#xff0c;被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用程序 Kafka 官网&#xff1a;Apache Kafka 关于ZooKeeper的弃用 根据 Kafka官网信息&#xff0c;随着Apache Kafka 3.5版本的发布&#xff0c;Zookeeper现…...

【LeetCode】 160. 相交链表

相交链表 题目题解 题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&am…...

TZOJ 1429 小明A+B

答案&#xff1a; #include <stdio.h> int main() {int T0, A0, B0, sum0;scanf("%d", &T); //输入测试数据的组数while (T--) //循环T次{scanf("%d %d", &A, &B); //输入AB的值sum A B;if (sum > 100) //如果是三位数{…...

制作openeuler的livecd

下载该项目&#xff0c;执行下面的操作gitee openeuler livecd项目 基于openeuler环境 #安装工具&#xff0c;第一次可能报错&#xff0c;可以再执行一次 make installx86 livecd-creator -d -v --config./config/euler_x86_64.ks --fslabeleuler-LiveCD --cachecache --log…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...

Xcode 16 集成 cocoapods 报错

基于 Xcode 16 新建工程项目&#xff0c;集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

数据分析六部曲?

引言 上一章我们说到了数据分析六部曲&#xff0c;何谓六部曲呢&#xff1f; 其实啊&#xff0c;数据分析没那么难&#xff0c;只要掌握了下面这六个步骤&#xff0c;也就是数据分析六部曲&#xff0c;就算你是个啥都不懂的小白&#xff0c;也能慢慢上手做数据分析啦。 第一…...