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

SpringBoot源码解读与原理分析(三十二)SpringBoot整合JDBC(一)JDBC组件的自动装配

文章目录

  • 前言
  • 第10章 SpringBoot整合JDBC
    • 10.1 SpringBoot整合JDBC的项目搭建
      • 10.1.1 初始化数据库
      • 10.1.2 整合项目
        • 10.1.2.1 导入JDBC和MySQL驱动依赖
        • 10.1.2.2 配置数据源
      • 10.1.3 编写业务代码
        • 10.1.3.1 编写与t_user表对应的实体类User
        • 10.1.3.2 编写Dao层代码
        • 10.1.3.3 编写Service层代码
      • 10.1.4 编写主启动类
      • 10.1.5 测试结果
    • 10.2 整合JDBC后的自动装配
      • 10.2.1 配置数据源
        • 10.2.1.1 DataSourceInitializerInvoker
          • (1)createSchema
          • (2)initialize
        • 10.2.1.2 DataSourceInitializerPostProcessor
      • 10.2.2 创建JdbcTemplate
      • 10.2.3 配置事务管理器

前言

在实际SpringBoot项目中,通常都离不开与数据库的交互,更多的选择是使用持久层框架MyBatis或SpringData等,而不是原生的spring-jdbc。

但学习SpringBoot整合JDBC场景下的组件装配,以及注解声明式事务的生效原理、控制流程、事务传播行为等,依旧是必要的,对后续学习SpringBoot整合持久层框架具有很大帮助。

第10章 SpringBoot整合JDBC

10.1 SpringBoot整合JDBC的项目搭建

10.1.1 初始化数据库

选择MySQL作为本项目的数据源,创建一个新的数据库springboot_demo和一个新表t_user:

CREATE DATABASE springboot_demo CHARACTER SET 'utf8mb4';CREATE TABLE t_user(id INT(11) NOT NULL AUTO_INCREMENT,NAME VARCHAR(20) NOT NULL,tel VARCHAR(20) NULL,PRIMARY KEY (id)
);

10.1.2 整合项目

10.1.2.1 导入JDBC和MySQL驱动依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency>
</dependencies>
10.1.2.2 配置数据源

在resources目录下新建application.properties文件,并配置数据源:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_demo?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

10.1.3 编写业务代码

10.1.3.1 编写与t_user表对应的实体类User
public class User {private Integer id;private String name;private String tel;// getter setter toString ...
}
10.1.3.2 编写Dao层代码
@Repository
public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void save(User user) {jdbcTemplate.update("insert into t_user (name, tel) values (?, ?)",user.getName(), user.getTel());}public List<User> findAll() {return jdbcTemplate.query("select * from t_user",BeanPropertyRowMapper.newInstance(User.class));}}
10.1.3.3 编写Service层代码
@Service
public class UserService {@Autowiredprivate UserDao userDao;@Transactional(rollbackFor = Exception.class)public void test() {User user = new User();user.setName("齐天大圣");user.setTel("12306");userDao.save(user);List<User> userList = userDao.findAll();userList.forEach(System.out::println);}}

10.1.4 编写主启动类

主启动类注意两点:第一是要获取IOC容器,并提取出UserService类调用其test方法;第二是要标注@EnableTransactionManagement注解开启注解式声明式事务。

@SpringBootApplication
@EnableTransactionManagement
public class JDBCApp {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(JDBCApp.class, args);UserService userService = context.getBean(UserService.class);userService.test();}}

10.1.5 测试结果

运行主启动类,控制台可以正确打印出一条用户信息,说明SpringBoot整合JDBC场景顺利完成。

User{id=1, name='齐天大圣', tel='12306'}

10.2 整合JDBC后的自动装配

由 10.1 节可知,对于原生的JDBC整合后,主启动类中并没有声明与之相关的注解,因此有关JDBC的组件装配都是以自动配置类的方式实现的。

借助IDEA通过spring-boot-autoconfigure依赖的spring.factories文件可以找到有关JDBC的自动配置类:

源码1:spring-boot-autoconfigure-2.3.11.RELEASE.jar!/META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

可以发现,SpringBoot默认支持的自动配置包含数据源、JdbcTemplate、事务管理器、JNDI、XA协议等。

10.2.1 配置数据源

在SpringBoot的官方文档中,介绍了SpringBoot支持的数据源连接池:

1.1.4. Supported Connection Pools
Spring Boot uses the following algorithm for choosing a specific implementation:
We prefer HikariCP for its performance and concurrency. If HikariCP is available, we always choose it.
Otherwise, if the Tomcat pooling DataSource is available, we use it.
Otherwise, if Commons DBCP2 is available, we use it.
If none of HikariCP, Tomcat, and DBCP2 are available and if Oracle UCP is available, we use it.

可见,SpringBoot支持的数据源连接池包括HikariCP、Tomcat、DBCP2、Oracle UCP等,默认使用HikariCP

因此,自动配置类DataSourceAutoConfiguration的静态内部类PooledDataSourceConfiguration会生效。因为它通过@Import注解导入了DataSourceConfiguration.Hikari类。

源码2DataSourceAutoConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {@Configuration(proxyBeanMethods = false)@Conditional(PooledDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,DataSourceJmxConfiguration.class })protected static class PooledDataSourceConfiguration {}
}
源码3DataSourceConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",matchIfMissing = true)
static class Hikari {@Bean@ConfigurationProperties(prefix = "spring.datasource.hikari")HikariDataSource dataSource(DataSourceProperties properties) {HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);if (StringUtils.hasText(properties.getName())) {dataSource.setPoolName(properties.getName());}return dataSource;}
}

由 源码2、3 可知,SpringBoot默认会创建一个HikariDataSource。

此外,DataSourceAutoConfiguration还使用@Import注解导入了一个DataSourceInitializationConfiguration配置类。

源码4DataSourceInitializationConfiguration.java@Configuration(proxyBeanMethods = false)
@Import({DataSourceInitializerInvoker.class, DataSourceInitializationConfiguration.Registrar.class})
class DataSourceInitializationConfiguration {static class Registrar implements ImportBeanDefinitionRegistrar {private static final String BEAN_NAME = "dataSourceInitializerPostProcessor";@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {if (!registry.containsBeanDefinition(BEAN_NAME)) {// 注册DataSourceInitializerPostProcessorGenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(DataSourceInitializerPostProcessor.class);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);beanDefinition.setSynthetic(true);registry.registerBeanDefinition(BEAN_NAME, beanDefinition);}}}}

由 源码4 可知,这个配置类又使用@Import注解导入了一个DataSourceInitializerInvoker和一个Registrar注册器。注册器又向BeanDefinition中注册了一个DataSourceInitializerPostProcessor。

10.2.1.1 DataSourceInitializerInvoker

由类名理解,这是一个数据源初始化的执行器

源码5DataSourceInitializerInvoker.javaclass DataSourceInitializerInvoker implements ApplicationListener<DataSourceSchemaCreatedEvent>, InitializingBean {@Overridepublic void afterPropertiesSet() {DataSourceInitializer initializer = getDataSourceInitializer();if (initializer != null) {boolean schemaCreated = this.dataSourceInitializer.createSchema();if (schemaCreated) {initialize(initializer);}}}}

由 源码5 可知,DataSourceInitializerInvoker实现了ApplicationListener接口,因此是一个监听器,监听的事件是DataSourceSchemaCreatedEvent;此外,它还实现了InitializingBean接口,会在对象创建后回调afterPropertiesSet方法执行初始化逻辑。

afterPropertiesSet方法中,首先会调用getDataSourceInitializer方法获取DataSourceInitializer实例,随后执行DataSourceInitializer的createSchema方法,如果执行成功则继续执行initialize方法。

(1)createSchema

该方法名直译为“创建约束”,即执行DDL语句。也就在项目开发中,可以先不创建数据库的表结构,而是在应用程序启动时,自动读取自定义的SQL文件执行DDL语句进行创建。

源码6DataSourceInitializer.javaboolean createSchema() {// 加载Schema资源List<Resource> scripts = getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");// 解析Schema资源if (!scripts.isEmpty()) {if (!isEnabled()) {logger.debug("Initialization disabled (not running DDL scripts)");return false;}String username = this.properties.getSchemaUsername();String password = this.properties.getSchemaPassword();runScripts(scripts, username, password);}return !scripts.isEmpty();
}private List<Resource> getScripts(String propertyName, List<String> resources, String fallback) {if (resources != null) {// 如果全局配置文件中配置了spring.datasource.schema属性// 则直接根据该spring.datasource.schema属性加载资源文件return getResources(propertyName, resources, true);}// 默认返回字符串"all"String platform = this.properties.getPlatform();List<String> fallbackResources = new ArrayList<>();// 拼接文件名:schema-all.sql和schema.sqlfallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");fallbackResources.add("classpath*:" + fallback + ".sql");// 加载文件schema-all.sql和schema.sqlreturn getResources(propertyName, fallbackResources, false);
}

由 源码6 可知,createSchema方法先读取全局配置文件中的spring.datasource.schema属性,根据该属性配置的路径加载资源文件,再对资源文件进行解析。在调用getScripts方法读取资源文件时,分为两种情况:

  • 如果全局配置文件中配置了spring.datasource.schema属性,则直接根据该属性的值加载资源文件;
  • 如果全局配置文件没有配置该属性,则加载名为schema-all.sql和schema.sql的资源文件。
(2)initialize
源码7DataSourceInitializerInvoker.javaprivate void initialize(DataSourceInitializer initializer) {try {// 广播DataSourceSchemaCreatedEvent事件this.applicationContext.publishEvent(new DataSourceSchemaCreatedEvent(initializer.getDataSource()));if (!this.initialized) {// 解析资源文件this.dataSourceInitializer.initSchema();this.initialized = true;}} // catch ......
}@Override
public void onApplicationEvent(DataSourceSchemaCreatedEvent event) {DataSourceInitializer initializer = getDataSourceInitializer();if (!this.initialized && initializer != null) {initializer.initSchema();this.initialized = true;}
}
源码8DataSourceInitializer.javavoid initSchema() {// 加载资源文件List<Resource> scripts = getScripts("spring.datasource.data", this.properties.getData(), "data");// 解析资源文件if (!scripts.isEmpty()) {if (!isEnabled()) {logger.debug("Initialization disabled (not running data scripts)");return;}String username = this.properties.getDataUsername();String password = this.properties.getDataPassword();runScripts(scripts, username, password);}
}

由 源码7 可知,initialize方法会广播一个DataSourceSchemaCreatedEvent事件,回调onApplicationEvent方法,最终执行DataSourceInitializer类的initSchema方法。

由 源码8 可知,initSchema方法和createSchema方法大同小异,不同的是initSchema方法寻找资源文件的依据是全局配置文件中的spring.datasource.data属性,如果没有配置该属性,则加载名为data-all.sql和data.sql的资源文件。

总结一下,有了DataSourceInitializerInvoker的设计,使得项目开发中,可以自定义DDL语句和DML语句并保存在SQL文件中,放置在resources目录下,在项目启动时自动初始化数据库表结构和数据。

10.2.1.2 DataSourceInitializerPostProcessor

由类名理解,这是一个专门为DataSourceInitializer定制的后置处理器。

源码9DataSourceInitializerPostProcessor.java@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof DataSource) {this.beanFactory.getBean(DataSourceInitializerInvoker.class);}return bean;
}

由 源码9 可知,当DataSourceInitializerPostProcessor检测到当前正在创建的bean对象的类型是DataSource,主动调用BeanFactory的getBean方法创建一个DataSourceInitializerInvoker对象。这样做的目的是使预定定义好的SQL脚本立即执行,以确保DataSource与数据库表结构、数据的同步初始化。

10.2.2 创建JdbcTemplate

源码10JdbcTemplateAutoConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {}

由 源码10 可知,自动配置类JdbcTemplateAutoConfiguration会使用@Import注解注册一个JdbcTemplateConfiguration配置类和一个NamedParameterJdbcTemplateConfiguration配置类。

源码11JdbcTemplateConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {@Bean@PrimaryJdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);JdbcProperties.Template template = properties.getTemplate();jdbcTemplate.setFetchSize(template.getFetchSize());jdbcTemplate.setMaxRows(template.getMaxRows());if (template.getQueryTimeout() != null) {jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());}return jdbcTemplate;}}

由 源码11 可知,JdbcTemplateConfiguration配置类会注册一个JdbcTemplate对象,用于与数据库的简单交互。

源码12NamedParameterJdbcTemplateConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(JdbcTemplate.class)
@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
class NamedParameterJdbcTemplateConfiguration {@Bean@PrimaryNamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) {return new NamedParameterJdbcTemplate(jdbcTemplate);}}

由 源码12 可知,NamedParameterJdbcTemplateConfiguration配置类会注册一个NamedParameterJdbcTemplate对象,用于支持参数命名化的JdbcTemplate增强。

10.2.3 配置事务管理器

源码13DataSourceTransactionManagerAutoConfiguration.java@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnSingleCandidate(DataSource.class)static class DataSourceTransactionManagerConfiguration {@Bean@ConditionalOnMissingBean(PlatformTransactionManager.class)DataSourceTransactionManager transactionManager(DataSource dataSource,ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));return transactionManager;}}}

由 源码13 可知,自动配置类DataSourceTransactionManagerAutoConfiguration会注册一个DataSourceTransactionManager,用于支持基于数据源的事务控制。

······

本节完,更多内容请查阅分类专栏:SpringBoot源码解读与原理分析

相关文章:

SpringBoot源码解读与原理分析(三十二)SpringBoot整合JDBC(一)JDBC组件的自动装配

文章目录 前言第10章 SpringBoot整合JDBC10.1 SpringBoot整合JDBC的项目搭建10.1.1 初始化数据库10.1.2 整合项目10.1.2.1 导入JDBC和MySQL驱动依赖10.1.2.2 配置数据源 10.1.3 编写业务代码10.1.3.1 编写与t_user表对应的实体类User10.1.3.2 编写Dao层代码10.1.3.3 编写Servic…...

petalinux_zynq7 驱动DAC以及ADC模块之五:nodejs+vue3实现web网页波形显示

前文&#xff1a; petalinux_zynq7 C语言驱动DAC以及ADC模块之一&#xff1a;建立IPhttps://blog.csdn.net/qq_27158179/article/details/136234296petalinux_zynq7 C语言驱动DAC以及ADC模块之二&#xff1a;petalinuxhttps://blog.csdn.net/qq_27158179/article/details/1362…...

Android java中内部类的使用

一.成员内部类 实验1&#xff1a;成员内部类 class Outer {private int a 10;class Inner {public void printInfo(){System.out.println("a "a);}}}public class InnerDemo {public static void main(String args[]) {Outer o new Outer();Outer.Inner i o.new…...

llm的inference(二)

文章目录 Tokenizer分词1.单词分词法2.单字符分词法3.子词分词法BPE(字节对编码&#xff0c;Byte Pair Encoding)WordPieceUnigram Language Model(ULM) embedding的本质推理时的一些指标参考链接 Tokenizer 在使用模型前&#xff0c;都需要将sequence过一遍Tokenizer&#xf…...

pytorch -- torch.nn.Module

基础 torch.nn 是 PyTorch 中用于构建神经网络的模块。nn.Module包含网络各层的定义及forward方法。 在用户自定义神经网络时&#xff0c;需要继承自nn.Module类。通过继承 nn.Module 类&#xff0c;您可以创建自己的神经网络模型&#xff0c;并定义模型的结构和操作。 torch.n…...

Microsoft Edge 越用越慢、超级卡顿?网页B站播放卡顿?

记录10个小妙招 Microsoft Edge 启动缓慢、菜单导航卡顿、浏览响应沉闷&#xff1f;这些情况可能是由于系统资源不足或浏览器没及时更新引起的。接下来&#xff0c;我们将介绍 10 种简单的方法&#xff0c;让 Edge 浏览器的速度重新起飞。 基础检查与问题解决 如果 Microsoft…...

XGB-9: 分类数据

从1.5版本开始&#xff0c;XGBoost Python包为公共测试提供了对分类数据的实验性支持。对于数值数据&#xff0c;切分条件被定义为 v a l u e < t h r e s h o l d value < threshold value<threshold &#xff0c;而对于分类数据&#xff0c;切分的定义取决于是否使用…...

FreeRTOS学习第8篇--同步和互斥操作引子

目录 FreeRTOS学习第8篇--同步和互斥操作引子同步和互斥概念实现同步和互斥的机制PrintTask_Task任务相关代码片段CalcTask_Task任务相关代码片段实验现象本文中使用的测试工程 FreeRTOS学习第8篇–同步和互斥操作引子 本文目标&#xff1a;学习与使用FreeRTOS中的同步和互斥操…...

c++STL容器的使用(vector, list, map, set等),c++STL算法的理解与使用(sort, find, binary_search等)

cSTL容器的使用&#xff08;vector, list, map, set等&#xff09; 在C的STL&#xff08;Standard Template Library&#xff09;中&#xff0c;容器是重要的一部分&#xff0c;它们提供了各种数据结构来存储和管理数据。以下是一些常见的STL容器及其使用方法的简要说明&#x…...

选择VR全景行业,需要了解哪些内容?

近年来&#xff0c;随着虚拟现实、增强现实等技术的持续发展&#xff0c;VR全景消费市场得以稳步扩张。其次&#xff0c;元宇宙行业的高速发展&#xff0c;也在进一步拉动VR全景技术的持续进步&#xff0c;带动VR产业的高质量发展。作为一种战略性的新兴产业&#xff0c;国家和…...

830. 单调栈

Problem: 830. 单调栈 文章目录 思路解题方法复杂度Code 思路 这是一个单调栈的问题。单调栈是一种特殊的栈结构&#xff0c;它的特点是栈中的元素保持单调性。在这个问题中&#xff0c;我们需要找到每个元素左边第一个比它小的元素&#xff0c;这就需要使用到单调递增栈。 我们…...

H5 个人引导页官网型源码

H5 个人引导页官网型源码 源码介绍&#xff1a;源码无后台、无数据库&#xff0c;H5自检测适应、无加密&#xff0c;直接修改可用。 源码含有多选项&#xff0c;多功能。可展示自己站点、团队站点。手机电脑双端。 下载地址&#xff1a; https://www.changyouzuhao.cn/1434.…...

【Linux】部署前后端分离项目---(Nginx自启,负载均衡)

目录 前言 一 Nginx&#xff08;自启动&#xff09; 2.1 Nginx的安装 2.2 设置自启动Nginx 二 Nginx负载均衡tomcat 2.1 准备两个tomcat 2.1.1 复制tomcat 2.1.2 修改server.xml文件 2.1.3 开放端口 2.2 Nginx配置 2.2.1 修改nginx.conf文件 2.2.2 重启Nginx服务 2…...

WPF Style样式设置

1.本window设置样式 <Window x:Class"WPF_Study.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expressi…...

【STM32】软件SPI读写W25Q64芯片

目录 W25Q64模块 W25Q64芯片简介 硬件电路 W25Q64框图 Flash操作注意事项 状态寄存器 ​编辑 指令集 INSTRUCTIONS​编辑 ​编辑 SPI读写W25Q64代码 硬件接线图 MySPI.c MySPI.h W25Q64 W25Q64.c W25Q64.h W25Q64_Ins.h main.c 测试 SPI通信&#xff08;W25…...

普通中小学校管理信息系统V1.1

普通中小学校管理信息系统 Ordinary Primary and Secondary Schools Management Information System 普通中小学校管理信息系统 Ordinary Primary and Secondary Schools Management Information System...

中国水果采摘机器人行业市场研究及发展趋势分析报告

全版价格&#xff1a;壹捌零零 报告版本&#xff1a;下单后会更新至最新版本 交货时间&#xff1a;1-2天 第一章 2016-2026年中国水果采摘机器人行业总概 1.1 中国水果采摘机器人行业发展概述 机器人技术的发展是一个国家高科技水平和工业自动化程度的重要标志和体现。机器…...

Linux多进程与信号

在多进程的服务程序中&#xff0c;如果子进程收到退出信号&#xff0c;子进程自行退出。如果父进程收到退出信号&#xff0c;应该先向全部的子进程发送退出信号&#xff0c;然后自己再退出。 演示demo程序 #include <iostream> // 包含输入输出流库&#xff0c;用于输…...

Self-attention与Word2Vec

Self-attention&#xff08;自注意力&#xff09;和 Word2Vec 是两种不同的词嵌入技术&#xff0c;用于将单词映射到低维向量空间。它们之间的区别&#xff1a; Word2Vec&#xff1a; Word2Vec 是一种传统的词嵌入&#xff08;word embedding&#xff09;方法&#xff0c;旨在为…...

【Flutter/Android】运行到安卓手机上一直卡在 Running Gradle task ‘assembleDebug‘... 的终极解决办法

方法步骤简要 查看你的Flutter项目需要什么版本的 Gradle 插件&#xff1a; 下载这个插件&#xff1a; 方法一&#xff1a;浏览器输入&#xff1a;https://services.gradle.org/distributions/gradle-7.6.3-all.zip 方法二&#xff1a;去Gradle官网找对应的版本&#xff1a;h…...

医疗实施-客户需求分析

在我的日常系统实施过程中&#xff0c;总会遇到不同角色的客户提出不同类别的需求。有的需求&#xff0c;客户目的想提高操作便携&#xff0c;但会对系统稳定性存在风险&#xff0c;应该拒掉。有些需求紧急而且影响重大&#xff0c;应该紧急处理。有些需求可以做&#xff0c;但…...

调度服务看门狗配置

查看当前服务器相关的sqlserver服务 在任务栏右键&#xff0c;选择点击启动任务管理器 依次点击&#xff0c;打开服务 找到sqlserver 相关的服务&#xff0c; 确认这些服务是启动状态 将相关服务在看门狗中进行配置 选择调度服务&#xff0c;双击打开 根据上面找的服务进行勾…...

AI时代 编程高手的秘密武器:世界顶级大学推荐的计算机教材

文章目录 01 《深入理解计算机系统》02 《算法导论》03 《计算机程序的构造和解释》04 《数据库系统概念》05 《计算机组成与设计&#xff1a;硬件/软件接口》06 《离散数学及其应用》07 《组合数学》08《斯坦福算法博弈论二十讲》 清华、北大、MIT、CMU、斯坦福的学霸们在新学…...

【数据结构和算法初阶(c语言)】数据结构前言,初识数据结构(给你一个选择学习数据结构和算法的理由)

1.何为数据结构 数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的 数据元素的集合。本质来讲就是在内存中去管理数据方式比如我们的增删查改。在内存中管理数据的方式有很多种&#xff08;比如数组结构、链式结构、树型结…...

LeetCode 0235.二叉搜索树的最近公共祖先:用搜索树性质(不遍历全部节点)

【LetMeFly】235.二叉搜索树的最近公共祖先&#xff1a;用搜索树性质&#xff08;不遍历全部节点&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/ 给定一个二叉搜索树, 找到该树中两个指定节点的最近公…...

【Prometheus】概念和工作原理介绍

目录 一、概述 1.1 prometheus简介 1.2 prometheus特点 1.3 prometheus架构图 1.4 prometheus组件介绍 1、Prometheus Server 2、Client Library 3、pushgateway 4、Exporters 5、Service Discovery 6、Alertmanager 7、grafana 1.5 Prometheus 数据流向 1.6 Pro…...

四川易点慧电子商务有限公司抖音小店:可靠之选,购物新体验

在当今这个网络购物日益盛行的时代&#xff0c;选择一家可靠的电商平台成为了消费者最为关心的问题之一。四川易点慧电子商务有限公司抖音小店作为新兴的电商力量&#xff0c;凭借其独特的魅力和优势&#xff0c;正逐渐成为众多消费者心中的可靠之选。 易点慧电子商务有限公司在…...

SpringBoot自带的tomcat的最大连接数和最大的并发数

先说结果&#xff1a;springboot自带的tomcat的最大并发数是200&#xff0c; 最大连接数是&#xff1a;max-connectionsaccept-count的值 再说一下和连接数相关的几个配置&#xff1a; 以下都是默认值&#xff1a; server.tomcat.threads.min-spare10 server.tomcat.threa…...

TLS1.2抓包解析

1.TLS1.2记录层消息解析 Transport Layer SecurityTLSv1.2 Record Layer: Handshake Protocol: Client HelloContent Type: Handshake (22)Version: TLS 1.0 (0x0301)Length: 253Content Type&#xff1a;消息类型&#xff0c;1个字节。 i 0Version&#xff1a;协议版本&…...

使用两个队列实现栈

在计算机科学中&#xff0c;栈是一种数据结构&#xff0c;它遵循后进先出&#xff08;LIFO&#xff09;的原则。这意味着最后一个被添加到栈的元素将是第一个被移除的元素。然而&#xff0c;Java的标准库并没有提供栈的实现&#xff0c;但我们可以使用两个队列来模拟一个栈的行…...

通过ffmpeg实现视频背景色替换

最近遇到一个需求&#xff0c;希望可以将素材视频的绿幕背景替换为指定的颜色&#xff0c;然后通过裁剪&#xff0c;拼接等处理制作一个新的视频。所以替换背景色成为了重要的一环&#xff0c;看能否通过ffmpeg来实现。通过一番搜索尝试&#xff0c;发现方案可行。下面我整理一…...

后轮位置反馈控制与算法仿真实现

文章目录 1. 后轮反馈控制2. 算法原理3. 算法和仿真实现 1. 后轮反馈控制 后轮反馈控制&#xff08;Rear wheel feedback&#xff09;算法是利用后轮中心的跟踪偏差来进行转向控制量计算的方法&#xff0c;属于Frenet坐标系的一个应用。通过选择合适的李雅普诺夫函数设计控制率…...

实战 vue3 使用百度编辑器ueditor

前言 在开发项目由于需求vue自带对编辑器不能满足使用&#xff0c;所以改为百度编辑器&#xff0c;但是在网上搜索发现都讲得非常乱&#xff0c;所以写一篇使用流程的文章 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、下载ueditor编辑器 一个“…...

N种方法解决1(CTF)

这里遇到的问题&#xff1a;一开始采用的base64解码平台有问题&#xff1b;默认解密出的格式为GBK格式&#xff1b;直接复制粘贴发现无法还原图片&#xff1b;又尝试了其他编码的&#xff1b;发现只有hex格式可以保证图片正常还原&#xff1b; 图片是以二进制存储的&#xff1…...

Istio实战:Istio Kiali部署与验证

目录 前言一、Istio安装小插曲 注意事项 二、Kiali安装三、Istio测试参考资料 前言 前几天我就开始捣腾Istio。前几天在执行istioctl install --set profiledemo -y 的时候老是在第二步就报错了&#xff0c;开始我用的istio版本是1.6.8。 后面查看k8s与istio的版本对应关系后发…...

ASPxGridView中使用PopupEditForm表单字段联动填充

c#中devexpress的控件ASPxGridView中使用PopupEditForm表单字段联动填充 //选择项目名称&#xff0c;自动填充项目编号 <Columns><dx:GridViewDataTextColumn FieldName"id" ReadOnly"True" VisibleIndex"0" Visible"False"…...

基于Pytorch的猫狗图片分类【深度学习CNN】

猫狗分类来源于Kaggle上的一个入门竞赛——Dogs vs Cats。为了加深对CNN的理解&#xff0c;基于Pytorch复现了LeNet,AlexNet,ResNet等经典CNN模型&#xff0c;源代码放在GitHub上&#xff0c;地址传送点击此处。项目大纲如下&#xff1a; 文章目录 一、问题描述二、数据集处理…...

flutter sliver 多种滚动组合开发指南

flutter sliver 多种滚动组合开发指南 视频 https://youtu.be/4mho1kZ_YQU https://www.bilibili.com/video/BV1WW4y1d7ZC/ 前言 有不少同学工作中遇到需要把几个不同滚动行为组件&#xff08;顶部 appBar、内容固定块、tabBar 切换、tabBarView视图、自适应高度、横向滚动&a…...

kafka生产者2

1.数据可靠 • 0&#xff1a;生产者发送过来的数据&#xff0c;不需要等数据落盘应答。 风险&#xff1a;leader挂了之后&#xff0c;follower还没有收到消息。。。。 • 1&#xff1a;生产者发送过来的数据&#xff0c;Leader收到数据后应答。 风险&#xff1a;leader应答…...

【LNMP】云导航项目部署及环境搭建(复杂)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍1.1项目环境架构LNMP1.2项目代码说明 二、项目环境搭建2.1 Nginx安装2.2 php安装2.3 nginx配置和php配置2.3.1 修改nginx文件2.3.2 修改vim /etc/p…...

nginx之状态页 日志分割 自定义图表 证书

5.1 网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状态 server{…...

数字人的未来:数字人对话系统 Linly-Talker + 克隆语音 GPT-SoVITS

&#x1f680;数字人的未来&#xff1a;数字人对话系统 Linly-Talker 克隆语音 GPT-SoVITS https://github.com/Kedreamix/Linly-Talker 2023.12 更新 &#x1f4c6; 用户可以上传任意图片进行对话 2024.01 更新 &#x1f4c6; 令人兴奋的消息&#xff01;我现在已经将强…...

SpringMVC 学习(五)之域对象

目录 1 域对象介绍 2 向 request 域对象共享数据 2.1 通过 ServletAPI (HttpServletRequest) 向 request 域对象共享数据 2.2 通过 ModelAndView 向 request 域对象共享数据 2.3 通过 Model 向 request 域对象共享数据 2.4 通过 map 向 request 域对象共享数据 2.5 通过…...

✅技术社区项目—JWT身份验证

通用的JWT鉴权方案 JWT鉴权流程 基本流程分三步: ● 用户登录成功之后&#xff0c;后端将生成的jwt返回给前端&#xff0c;然后前端将其保存在本地缓存; ● 之后前端与后端的交互时&#xff0c;都将iwt放在请求头中&#xff0c;比如可以将其放在Http的身份认证的请求头 Author…...

5.2 Ajax 数据爬取实战

目录 1. 实战内容 2、Ajax 分析 3、爬取内容 4、存入MySQL 数据库 4.1 创建相关表 4.2 数据插入表中 5、总代码与结果 1. 实战内容 爬取Scrape | Movie的所有电影详情页的电影名、类别、时长、上映地及时间、简介、评分&#xff0c;并将这些内容存入MySQL数据库中。 2、…...

276.【华为OD机试真题】矩阵匹配(二分法—JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-矩阵匹配二.解题思路三.题解代码Python题解代码…...

java——多线程基础

目录 线程的概述多线程的创建方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runnable接口方式三&#xff1a;利用Callable接口、FutureTask类来实现。Thread常用的方法 线程安全问题线程安全问题概述线程安全问题案例取钱案例描述模拟代码如下&#xff1a;执行结果 线程…...

Python服务器监测测试策略与工具:确保应用的高可用性!

在构建高可用性的应用程序时&#xff0c;服务器监测测试是至关重要的一环。Python作为一种强大的编程语言&#xff0c;提供了丰富的工具和库来帮助我们进行服务器监测测试。本文将介绍一些关键的策略和工具&#xff0c;帮助你确保应用的高可用性。 1. 监测策略的制定&#xff…...

Spring Security源码学习

Spring Security本质是一个过滤器链 过滤器链本质是责任链设计模型 1. HttpSecurity 【第五篇】深入理解HttpSecurity的设计-腾讯云开发者社区-腾讯云 在以前spring security也是采用xml配置的方式&#xff0c;在<http>标签中配置http请求相关的配置&#xff0c;如用户…...

大数据面试总结三

1、hdfs作为分布式存储系统&#xff0c;底层的实现的方式&#xff08;可能不正确&#xff09; 1、底层是一个分布式存储的&#xff0c;底层会将数据进行切分多个block块&#xff08;128M&#xff09;&#xff0c;并存储在不同的节点上面&#xff0c;这种分布式方式有助于提高数…...