Spring Boot中配置多个数据源

配置数据源实际上就是配置多个数据库,在一个配置文件中配置多个数据库,这样做主要的好处有以下几点:

  1. 数据库隔离:通过配置多个数据源,可以将不同的业务数据存储在不同的数据库中,实现数据的隔离。这样可以提高系统的安全性和稳定性,避免不同业务之间的数据相互干扰。
  2. 性能优化:通过配置多个数据源,可以将读写操作分离到不同的数据库中,从而提高系统的并发性能。例如,将读操作集中在一个主数据库中,将写操作分散到多个从数据库中,可以有效地减轻数据库的读写压力,提高系统的响应速度。
  3. 扩展性:当系统需要扩展到多个地理位置或多个数据中心时,配置多个数据源可以更好地支持分布式部署。每个地理位置或数据中心可以配置一个独立的数据源,使得数据访问更加高效和可靠。
  4. 多租户支持:对于多租户的系统,配置多个数据源可以实现不同租户的数据隔离。每个租户可以拥有自己独立的数据库,从而保证数据的安全性和隐私性。
  5. 数据库版本升级:在进行数据库版本升级时,可以通过配置多个数据源,将新版本的数据库与旧版本的数据库并行使用。这样可以在升级过程中保证系统的正常运行,减少升级带来的风险。

我们目前常用的三种数据访问方法方式:

  1. JDBCTemplate
  2. Spring Data JPA
  3. MyBatis

接下来我们将围绕这种数据访问方法进行配置:

JDBCTemplate

实际上这种方式,主要还是在application.properties中设置我们需要链接的数据库配置,比如我A数据库用来存储用户信息,B数据库用来存储业务数据。

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

ok,我们继续配置完毕后数据源后,我们就通过配置类来完成加载这些配置信息,初始话数据源,以及初始化每个数据源的时候要用的JDBCTemplate。你只需要在你的Spring Boot中应用下面的配置类就可以完成。

@Configuration
public class DataSourceConfiguration {@Primary@Bean@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return DataSourceBuilder.create().build();}@Beanpublic JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource primaryDataSource) {return new JdbcTemplate(primaryDataSource);}@Beanpublic JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {return new JdbcTemplate(secondaryDataSource);}}
	<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

单元测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {@Autowiredprotected JdbcTemplate primaryJdbcTemplate;@Autowiredprotected JdbcTemplate secondaryJdbcTemplate;@Beforepublic void setUp() {primaryJdbcTemplate.update("DELETE  FROM  USER ");secondaryJdbcTemplate.update("DELETE  FROM  USER ");}@Testpublic void test() throws Exception {// 往第一个数据源中插入 2 条数据primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "aaa", 20);primaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "bbb", 30);// 往第二个数据源中插入 1 条数据,若插入的是第一个数据源,则会主键冲突报错secondaryJdbcTemplate.update("insert into user(name,age) values(?, ?)", "ccc", 20);// 查一下第一个数据源中是否有 2 条数据,验证插入是否成功Assert.assertEquals("2", primaryJdbcTemplate.queryForObject("select count(1) from user", String.class));// 查一下第一个数据源中是否有 1 条数据,验证插入是否成功Assert.assertEquals("1", secondaryJdbcTemplate.queryForObject("select count(1) from user", String.class));}
}

有两个JdbcTemplate,为什么不用@Qualifier指定?这里顺带说个小知识点,当我们不指定的时候,会采用参数的名字来查找Bean,存在的话就注入。

这两个JdbcTemplate创建的时候,我们也没指定名字,它们是如何匹配上的?这里也是一个小知识点,当我们创建Bean的时候,默认会使用方法名称来作为Bean的名称,所以这里就对应上了。读者不妨回头看看两个名称是不是一致的。

Spring Data JPA

和上边那种方式基本上类似,所做的操作会有细微的区别。

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

配置application.properties文件

# pring boot 1.x的配置:spring.datasource.primary.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver# spring boot 1.x的配置:spring.datasource.secondary.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver# 日志打印执行的SQL
spring.jpa.show-sql=true
# Hibernate的DDL策略
spring.jpa.hibernate.ddl-auto=create-drop

创建实体类:

@Entity
//@Data
//@NoArgsConstructor
public class User {@Id@GeneratedValueprivate Long id;private String name;private Integer age;public User(String name, Integer age) {this.name = name;this.age = age;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public User() {}
}
public interface UserRepository extends JpaRepository<User, Long> {}
@Entity
//@Data
//@NoArgsConstructor
public class Message {@Id@GeneratedValueprivate Long id;private String title;private String message;public Message(String title, String message) {this.title = title;this.message = message;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Message() {}
}
public interface MessageRepository extends JpaRepository<Message, Long> {}

多数据源配置类:

@Configuration
public class DataSourceConfiguration {@Primary@Bean@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return DataSourceBuilder.create().build();}}

主数据源配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef="entityManagerFactoryPrimary",transactionManagerRef="transactionManagerPrimary",basePackages= { "com.miaow.demo.p" }) //设置Repository所在位置
public class PrimaryConfig {@Autowired@Qualifier("primaryDataSource")private DataSource primaryDataSource;@Autowiredprivate JpaProperties jpaProperties;@Autowiredprivate HibernateProperties hibernateProperties;private Map<String, Object> getVendorProperties() {return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());}@Primary@Bean(name = "entityManagerPrimary")public EntityManager entityManager(EntityManagerFactoryBuilder builder) {return entityManagerFactoryPrimary(builder).getObject().createEntityManager();}@Primary@Bean(name = "entityManagerFactoryPrimary")public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
//        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
//        jpaVendorAdapter.setGenerateDdl(true);return builder.dataSource(primaryDataSource).packages("com.miaow.demo.p") //设置实体类所在位置.persistenceUnit("primaryPersistenceUnit").properties(getVendorProperties()).build();}@Primary@Bean(name = "transactionManagerPrimary")public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());}
}

设置从数据库配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef="entityManagerFactorySecondary",transactionManagerRef="transactionManagerSecondary",basePackages= { "com.miaow.demo.s" }) //设置Repository所在位置
public class SecondaryConfig {@Autowired@Qualifier("secondaryDataSource")private DataSource secondaryDataSource;@Autowiredprivate JpaProperties jpaProperties;@Autowiredprivate HibernateProperties hibernateProperties;private Map<String, Object> getVendorProperties() {return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());}@Bean(name = "entityManagerSecondary")public EntityManager entityManager(EntityManagerFactoryBuilder builder) {return entityManagerFactorySecondary(builder).getObject().createEntityManager();}@Bean(name = "entityManagerFactorySecondary")public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {return builder.dataSource(secondaryDataSource).packages("com.miaow.demo.s") //设置实体类所在位置.persistenceUnit("secondaryPersistenceUnit").properties(getVendorProperties()).build();}@Bean(name = "transactionManagerSecondary")PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());}}

创建的单元测试:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {@Autowiredprivate UserRepository userRepository;@Autowiredprivate MessageRepository messageRepository;@Testpublic void test() throws Exception {userRepository.save(new User("aaa", 10));userRepository.save(new User("bbb", 20));userRepository.save(new User("ccc", 30));userRepository.save(new User("ddd", 40));userRepository.save(new User("eee", 50));Assert.assertEquals(5, userRepository.findAll().size());messageRepository.save(new Message("o1", "aaaaaaaaaa"));messageRepository.save(new Message("o2", "bbbbbbbbbb"));messageRepository.save(new Message("o3", "cccccccccc"));Assert.assertEquals(3, messageRepository.findAll().size());}}

MyBatis

在Spring Boot的配置文件application.properties中设置我们需要的两个连接的数据库配置:

# pring boot 1.x的配置:spring.datasource.primary.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver# spring boot 1.x的配置:spring.datasource.secondary.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver#mybatis.mapper-locations=classpath:mapper/*.xml

创建一个初始化多数据源和MyBatis配置

@Configuration
public class DataSourceConfiguration {@Primary@Bean@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return DataSourceBuilder.create().build();}}

可以看到内容跟JdbcTemplateSpring Data JPA的时候是一模一样的。通过@ConfigurationProperties可以知道这两个数据源分别加载了spring.datasource.primary.*spring.datasource.secondary.*的配置。@Primary注解指定了主数据源,就是当我们不特别指定哪个数据源的时候,就会使用这个Bean真正差异部分在下面的JPA配置上。

分别创建这两个数据源的MyBatis配置文件:
Private 数据源的JPA的配置文件:

@Configuration
@MapperScan(basePackages = "com.miaow.demo.p",sqlSessionFactoryRef = "sqlSessionFactoryPrimary",sqlSessionTemplateRef = "sqlSessionTemplatePrimary")
public class PrimaryConfig {private DataSource primaryDataSource;public PrimaryConfig(@Qualifier("primaryDataSource") DataSource primaryDataSource) {this.primaryDataSource = primaryDataSource;}@Beanpublic SqlSessionFactory sqlSessionFactoryPrimary() throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(primaryDataSource);return bean.getObject();}@Beanpublic SqlSessionTemplate sqlSessionTemplatePrimary() throws Exception {return new SqlSessionTemplate(sqlSessionFactoryPrimary());}}

Secondary的数据源JPA配置:

@Configuration
@MapperScan(basePackages = "com.miaow.demo.s",sqlSessionFactoryRef = "sqlSessionFactorySecondary",sqlSessionTemplateRef = "sqlSessionTemplateSecondary")
public class SecondaryConfig {private DataSource secondaryDataSource;public SecondaryConfig(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {this.secondaryDataSource = secondaryDataSource;}@Beanpublic SqlSessionFactory sqlSessionFactorySecondary() throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(secondaryDataSource);return bean.getObject();}@Beanpublic SqlSessionTemplate sqlSessionTemplateSecondary() throws Exception {return new SqlSessionTemplate(sqlSessionFactorySecondary());}}

注意在此说明一下,配置类上使用@MapperScan注解来指定当前数据源下定义的EntityMapper的包路径;
另外需要指定sqlSessionFactorysqlSessionTemplate,这两个具体实现在该配置类中类中初始化。
配置类的构造函数中,通过@Qualifier注解来指定具体要用哪个数据源,其名字对应在DataSourceConfiguration配置类中的数据源定义的函数名。
配置类中定义SqlSessionFactorySqlSessionTemplate的实现,注意具体使用的数据源正确。

创建一个UserPrimary实体类:

public class UserPrimary {private Long id;private String name;private Integer age;public UserPrimary(String name, Integer age) {this.name = name;this.age = age;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public UserPrimary() {}
}

创建一个UserMapperPrimary用来作为填写SQL语句的接口:

public interface UserMapperPrimary {@Select("SELECT * FROM USER WHERE NAME = #{name}")UserPrimary findByName(@Param("name") String name);@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")int insert(@Param("name") String name, @Param("age") Integer age);@Delete("DELETE FROM USER")int deleteAll();}

创建一个UserSecondary实体类:

public class UserSecondary {private Long id;private String name;private Integer age;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public UserSecondary() {}public UserSecondary(String name, Integer age) {this.name = name;this.age = age;}
}
public interface UserMapperSecondary {@Select("SELECT * FROM USER WHERE NAME = #{name}")UserSecondary findByName(@Param("name") String name);@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")int insert(@Param("name") String name, @Param("age") Integer age);@Delete("DELETE FROM USER")int deleteAll();
}

之后,也是最关键的一步,我们需要在MyBatis的配置文件中使用Mapper.xml
在Resources目录下创建一个mapper文件夹,之后再mapper文件夹下边分别创建primary和secondary文件夹:
在这里插入图片描述
UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.miaow.demo.p.mapper.UserMapperPrimary"><select id="findByName" resultType="com.miaow.demo.p.entity.UserPrimary">SELECT * FROM USER WHERE NAME = #{name}</select><insert id="insert">INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})</insert></mapper>

与上边这个几乎一样,只是两者指向的接口位置不一样:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.miaow.demo.s.mapper.UserMapperSecondary"><select id="findByName" resultType="com.miaow.demo.s.entity.UserSecondary">SELECT * FROM USER WHERE NAME = #{name}</select><insert id="insert">INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})</insert></mapper>

最后我们可以通过一个测试类进行测试:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class ApplicationTests {//第一数据库配置类@Autowiredprivate UserMapperPrimary userMapperPrimary;//第二数据库配置文件@Autowiredprivate UserMapperSecondary userMapperSecondary;@Beforepublic void setUp() {// 清空测试表,保证每次结果一样userMapperPrimary.deleteAll();userMapperSecondary.deleteAll();}@Testpublic void test() throws Exception {// 往Primary数据源插入一条数据userMapperPrimary.insert("AAA", 20);// 从Primary数据源查询刚才插入的数据,配置正确就可以查询到UserPrimary userPrimary = userMapperPrimary.findByName("AAA");Assert.assertEquals(20, userPrimary.getAge().intValue());// 从Secondary数据源查询刚才插入的数据,配置正确应该是查询不到的UserSecondary userSecondary = userMapperSecondary.findByName("AAA");Assert.assertNull(userSecondary);// 往Secondary数据源插入一条数据userMapperSecondary.insert("BBB", 20);// 从Primary数据源查询刚才插入的数据,配置正确应该是查询不到的userPrimary = userMapperPrimary.findByName("BBB");Assert.assertNull(userPrimary);// 从Secondary数据源查询刚才插入的数据,配置正确就可以查询到userSecondary = userMapperSecondary.findByName("BBB");Assert.assertEquals(20, userSecondary.getAge().intValue());}}

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

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

相关文章

Leetcode—637.二叉树的层平均值【简单】

2023每日刷题&#xff08;二十五&#xff09; Leetcode—637.二叉树的层平均值 BFS实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ /*** Note: The returned array mu…

vscode文件跳转(vue项目)

在 .vue 文件中&#xff0c;点击组件名打开 方式1&#xff1a; 在 vue 组件名上&#xff0c;桉住ctrl 鼠标左键 // 重新打开一个tab 方式2&#xff1a; 在 vue 组件名上&#xff0c;桉住ctrl shift 鼠标左键 // 在右侧拆分&#xff0c;并打开一个tab .vue文件的跳转 按住 …

漏刻有时百度地图API实战开发(1)华为手机无法使用addEventListener click 的兼容解决方案

漏刻有时百度地图API实战开发(1)华为手机无法使用addEventListener click 的兼容解决方案漏刻有时百度地图API实战开发(2)文本标签显示和隐藏的切换开关漏刻有时百度地图API实战开发(3)自动获取地图多边形中心点坐标漏刻有时百度地图API实战开发(4)显示指定区域在移动端异常的解…

龙芯loongarch64服务器编译安装scipy

前言 根据我之前的文章介绍,龙芯loongarch64服务器中的很多python依赖包安装有问题,发现其中安装的"scikit-learn"就无法正常使用,所有这里在 pip3 install scikit-learn -U -i https://pypi.tuna.tsinghua.edu.cn/simple 的时候发现"scipy"就无法正常…

轻松下载网页音频和视频

在网页上看到好看的视频或者听到的音乐想保存&#xff0c;让我来教你&#xff08;仅供学习&#xff09; 注意&#xff1a;有极少部分的网站视频经过加密&#xff0c;无法下载 一、视频下载 1.打开视频网页 2.右键“检查” 3.刷新网页 4.按照下图中步骤操作 5.把复制的链接放…

数字化工厂管理系统的三个关键技术是什么

随着科技的飞速发展&#xff0c;数字化工厂管理系统已经成为了现代制造业的重要发展方向。数字化工厂管理系统通过充分运用建模技术、仿真技术和单一数据源技术&#xff0c;实现了产品设计和生产的虚拟化&#xff0c;为制造业带来了前所未有的效率和创新能力。本文将深入探讨这…

k8s configMap挂载(项目配置文件放到configMap中,不同环境不同配置)

背景说明 项目对接配置文件加密&#xff0c;比如数据库密码、redis密码等。但是密文只能放到指定的配置文件中(important.properties)&#xff0c;该配置文件又不能接收环境变量&#xff0c;所以就很难区分不同环境的不同配置&#xff08;不同环境的数据库密码、redis密码一般…

Gui基础使用之项目部署

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.gui图形化界面的使用 1.1 前期准备 新建仓库&#xff0c;具体操作如下&#xff1a; 初始化readme文件&…

软件测试面试会问哪些问题?

软件测试面试&#xff0c;一般会被问到下面这九类问题。 1、基础问题 2、Linux命令 3、数据库 4、功能测试 5、Python基础 6、接口测试 7、自动化测试 8、性能测试 9、人事问题 接下来&#xff0c;以上9类问题&#xff0c;我都会分别结合2个案例&#xff0c;附上答案&#xff0…

Banana Pi BPI-M6(Raspberry Pi 5 替代品)初始设置及固件烧录

Banana Pi BPI-M6&#xff1a;初始设置和镜像烧录 Banana Pi BPI-M6 的首次测试 在上一篇文章中&#xff0c;我比较了Banana Pi BPI-M6和Raspberry Pi 5的硬件特性。两者都拥有出色的硬件技术&#xff0c;在性能方面应该不会有太大的问题。 今天我想测试一下 Banana Pi。作为…

阿里云双11优惠云服务器99元一年,4年396元

阿里云99元服务器新老用户均可以买&#xff0c;你没看错&#xff0c;老用户可以买&#xff0c;活动页面 aliyunfuwuqi.com/go/aliyun 配置为云服务器ECS经济型e实例、2核2G、3M固定带宽、40G ESSD Entry云盘&#xff0c;并且续费不涨价&#xff0c;原价99元即可续费&#xff0c…

【全网首发】【Python】Python控制parrot ARDrone 2.0无人机

&#x1f389;欢迎来到Python专栏~Python控制parrot ARDrone 2.0无人机 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文中出现错误…

AIGC:使用生成对抗网络GAN实现MINST手写数字图像生成

1 生成对抗网络 生成对抗网络&#xff08;Generative Adversarial Networks, GAN&#xff09;是一种非常经典的生成式模型&#xff0c;它受到双人零和博弈的启发&#xff0c;让两个神经网络在相互博弈中进行学习&#xff0c;开创了生成式模型的新范式。从 2017 年以后&#x…

vue项目js原生属性IntersectionObserver实现图片懒加载

vue项目js原生属性IntersectionObserver实现图片懒加载 IntersectionObserver 使用js原生属性IntersectionObserver实现观察img元素是否处于游览器视口中 懒加载原理&#xff1a;给img设置一个默认url图片&#xff0c;观察图片处于视口内以后&#xff0c;动态改变img的url为自己…

如何利用产品帮助中心提升用户体验

在当今竞争激烈的市场中&#xff0c;提供优秀的用户体验是吸引和保留客户的关键。而一个高效和易于使用的产品帮助中心&#xff0c;正成为越来越多企业用以提升用户体验的重要工具。产品帮助中心是一个集中的信息库&#xff0c;为用户提供关于产品功能、故障排除、常见问题解答…

SQL Server SSIS的安装

标题SQL SERVER 安装 下载SQL SERVER数据库&#xff1a;&#xff08;以SQL SERVER 2022 Developer版本&#xff09;(https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads?rtc1) 以administrator权限安装&#xff1a; 下载完成后&#xff0c;会出现以下界面&a…

GPIO实验:ARM汇编代码实现LED灯亮灭控制

GPIO实验&#xff1a;ARM汇编代码实现LED灯亮灭控制 一、 汇编工程模板Makefile分析 NAMEasm-led #指定编译的源文件名字 CROSS_COMPILE arm-linux-gnueabihf- #指定交叉编译工具链前缀CC $(CROSS_COMPILE)gcc #指定gcc名字LD $(CROSS_COMPILE)ld #指定链接器名字…

pytorch直线拟合

目录 1、数据分析 2、pytorch直线拟合 1、数据分析 直线拟合的前提条件通常包括以下几点&#xff1a; 存在线性关系&#xff1a;这是进行直线拟合的基础&#xff0c;数据点之间应该存在一种线性关系&#xff0c;即数据的分布可以用直线来近似描述。这种线性关系可以是数据点…

【hcie-cloud】【2】华为云Stack解决方案介绍、缩略语整理 【下】

文章目录 华为文档获取方式、云计算发展背景、坚实基座华为云Stack&#xff0c;政企只能升级首选智能数据湖仓一体&#xff0c;让业务洞见更准&#xff0c;价值兑现更快MRS&#xff1a;一个架构可构建三种数据湖&#xff0c;业务场景更丰富离线数据湖&#xff1a;提供云原生、湖…

使用jdk21预览版 --enable-preview

异常 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project sb3: Compilation failure [ERROR] --enable-preview 一起使用时无效 [ERROR] &#xff08;仅发行版 21 支持预览语言功能&#xff09; 解决…