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

Spring boot 知识整理

一、SpringBoot 背景内容梳理

  • SpringBoot是一个基于Spring框架的开源框架,用于简化Spring应用程序的初始搭建和开发过程。它通过提供约定优于配置的方式,尽可能减少开发者的工作量,使得开发Spring应用变得更加快速、便捷和高效。

  • SpringBoot的主要特点包括:

  1. 简化配置:SpringBoot遵循约定优于配置的原则,减少了传统Spring应用中的大量配置。它通过自动配置(auto-configuration)和起步依赖(starterdependencies)来简化项目的配置过程,让开发者可以快速搭建起一个可运行的Spring应用。
  2. 集成性强:SpringBoot提供了大量的开箱即用的特性和功能,如内嵌的Servlet容器(如Tomcat、Jetty或Undertow)、健康检查、指标监控等。它还整合了诸多常用的库和框架,如SpringData、SpringSecurity等,使得开发者可以快速构建出功能完善的应用。
  3. 微服务支持:SpringBoot非常适合用于构建微服务架构。它提供了丰富的支持,如通过SpringCloud进行微服务架构的开发,集成了服务发现、配置中心、负载均衡等功能,帮助开发者构建可伸缩、高可用的微服务系统。
  4. 内嵌服务器:SpringBoot可以将应用程序打包成一个可执行的JAR文件,并内置了常用的Servlet容器,如Tomcat、Jetty或Undertow。这样一来,开发者可以通过简单的java-jar命令来运行应用程序,而无需部署到外部应用服务器。
  5. 生态丰富:由于SpringBoot的广泛应用和强大生态系统,开发者可以轻松地使用各种扩展和插件,如Actuator、SpringBootDevTools等,提高开发效率和应用质量。
  • 从前端的api到我后端的接受再到数据库:
    • 发请求——>控制层接受——> 调用服务层的函数——>调用Repository——>找到对应的实体然后进行数据库的交互

其中额外设计的有 Response 的设计 ,方便前端对于后端返回数据的统一规范处理;
DTO类(用于封装数据,通常在层与层之间传递,避免直接暴露实体);
转换器的设计,方便后端设置哪些数据可以返回给对应的前端

二、Rest api 规范

  • 路径

    • 路径又称"终点”(endpoint),表示API的具体网址。
    • 在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。
  • Http 动词

    • GET(SELECT):从服务器取出资源(一项或多项)。
    • POST(CREATE):在服务器新建一个资源。
    • PUT(UPDATE):在服务器更新资源(将户端提供改变后的完整资源)。
    • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
    • DELETE(DELETE):从服务器删除资源。

三、JPA

JPA 提供了一种标准化的方式来进行对象关系映射,是 Java 应用程序中进行数据持久化的关键技术。通过使用 JPA,开发者可以更高效地管理数据库操作,专注于业务逻辑开发

JPA 是一个规范,多个框架实现了该规范,常见的实现包括:

  • Hibernate:最流行的 JPA 实现,提供丰富的功能和强大的社区支持。
  • EclipseLink:Oracle 官方的 JPA 实现,支持多种数据库。
  • OpenJPA:Apache 提供的 JPA 实现。

3.1. JPA内部有关的注解

1. @Entity

  • 定义:标识一个类为 JPA 实体,表示该类对应于数据库中的一张表。

2. @Table

  • 定义:指定实体类对应的数据库表的名称。
  • 用法@Table(name = "table_name")

3. @Id`

  • 定义:标识实体类的主键字段。

4. @GeneratedValue`

  • 定义:指定主键的生成策略。
  • 常用策略
    • GenerationType.IDENTITY:主键由数据库自动生成。
    • GenerationType.SEQUENCE:使用数据库序列生成主键。
    • GenerationType.AUTO:根据数据库自动选择生成策略。

5. @Column`

  • 定义:映射实体类的字段到数据库表的列。
  • 常用属性
    • name:指定数据库列名。
    • nullable:指定该列是否可以为 null
    • length:指定字符串列的最大长度。

6.@Builder

  • 用于简化对象的构建过程。它通过生成一个构建器模式的实现,减少频繁的属性赋值
  • 用法:
Student student = Student.builder() .name("Alice") .age(20).email("alice@example.com") .build();

3.2. JPA 的使用(JpaRepository<T, ID>)

  • JpaRepository<T, ID>是一个 Spring Data JPA 提供的接口,允许你执行 CRUD 操作。

    • 第一个泛型参数 T 表示实体类的类型,即与数据库相对应的Java类
    • 第二个泛型参数 ID 表示主键的类型,即用于唯一标识实体的字段,确保记录的唯一性(通常是 Long, Integer, String 等)
    • 必须遵循 JpaRepository<实体类, 主键类型> 的格式。交换位置会导致错误。
  • JPA的方法用法:

    • 基本 CRUD 操作
      • 通过继承 JpaRepository,可以获得基本的 CRUD 操作,如 save(), findById(), delete(), findAll() 等。
    • 查询方法命名约定
      • JPA 提供了一种约定优于配置的方法命名规则。你可以通过特定的命名规则自动生成查询。
      • 示例:
        • findByEmail(String email):根据 email 查找学生。
        • findByAgeBetween(int min, int max):查找年龄在 minmax 之间的学生。
        • findByNameStartingWith(String namePrefix):查找姓名以 namePrefix 开头的学生。
    • 使用 @Query 注解
      • 可以使用 @Query 注解来定义自定义查询。
      • 原始 SQL 查询
        • 使用 nativeQuery = true 指定这是一个原始 SQL 查询。
        • 示例:
@Query(value = "select * from Student   where  email = :email", nativeQuery = true)  
List<Student> findByEmail2(@Param("email") String email);query里面的用 :email 做占位符,用来读取@Parm 中的形参

.
- JPQL 查询
- JPQL 用于面向对象的查询,允许你直接操作实体。
- 使用 SELECT NEW 创建新对象。
- 示例:`findByEmail3(@Param(“email”) String email)

@Query(value = "SELECT NEW com.demo.springbootstudy.dao.Student(s.name, s.email) FROM Student s WHERE s.email = :email")  
List<Student> findByEmail3(@Param("email") String email);query里面的用 :email 做占位符,用来读取@Parm 中的形参

3.3 JpaSpecificationExecutor< T > 的使用

JpaSpecificationExecutor 是 Spring Data JPA 提供的接口,用于支持动态查询。通过该接口,可以使用 JPA Criteria API 构建复杂的查询条件.
.
在面对一个大项目,里面复杂的查询情况,可以单独创建一个文件夹存放不同实体的 Specification的静态定义,后续在服务层根据对应的情况,设置不同属性进行传参调用静态函数

使用:

  • 创建Repority接口去继承 JpaSpecificationExecutor< T >(其中T指的是数据库表实体)
  • 定义一个类存放Specification的静态方法,模板如下:
public static Specification<Student> filterByCriteria(StudentDTO studentDTO) {  return (root, query, cb) -> {  List<Predicate> predicates = new ArrayList<>();  if (studentDTO.getName() != null) {  predicates.add(cb.equal(root.get("name"), studentDTO.getName()));  }  if (studentDTO.getMinAge() != null) {  predicates.add(cb.greaterThanOrEqualTo(root.get("age"), studentDTO.getMinAge()));  }  if (studentDTO.getMaxAge() != null) {  predicates.add(cb.lessThanOrEqualTo(root.get("age"), studentDTO.getMaxAge()));  }  //两个 return 实现的效果一样return query.where(predicates.toArray(new Predicate[0])).getRestriction();return cb.and(predicates.toArray(new Predicate[0]));  };  
}- `root`:表示查询的根实体,即在这里是 `Student`。
- `query`:表示查询的上下文。
- `cb`:表示构建条件的 `CriteriaBuilder`对象。- 其中这个cb里面集成多种方法用于构建查询条件- cb.and(predicates.toArray(new Predicate[0])); - 动态地将所有的查询条件结合起来,形成一个整体的查询条件
- `Predicate`:表示查询条件,通过add函数来添加不同的查询条件- .getRestriction() 用于获取它所表示的条件
  • 后续调用先构建好对应的形参,然后调用上面的静态方法获取Specification;
  • 最后调用Repository接口中的函数findAll,形参传入的是上面的Specification对象;

3.4 分页查找的用法

四、Mybatis 的用法

MyBatis 是一个 持久层框架,用于简化数据库操作。它提供了一种映射关系,将数据库中的记录映射到 Java 对象,并支持通过 XML 或注解的方式配置 SQL 语句。
.
MyBatis Plus 是在 MyBatis 的基础上开发的增强工具包,旨在简化开发,提高效率。它提供了 CRUD 操作、条件构造器、分页插件、代码生成器等多种功能。

4.1 配置

Pom.xml 配置

<dependencies><!-- MyBatis Plus 依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!-- MySQL 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!-- 其他依赖 --><!-- ... -->
</dependencies>

Spring Boot 配置(以 .yml 文件为主)

spring:datasource:url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: your_usernamepassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl //sql打印到控制台

编写实体类

@Data
@TableName(value = "user")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;// @TableField(fill = FieldFill.INSERT, value = "create_time")// private Long createTime;// @TableField(fill = FieldFill.INSERT_UPDATE, value = "update_time")// private Long updateTime;// @Version// private Long version;
}

编写Mapper接口

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

添加注解MapperScan

在Application类上添加@MapperScan注解并指定mapper的包路径

Mybatis-plus 拦截器配置

配置类用于添加拦截器,如乐观锁、分页等插件

@Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加乐观锁拦截器 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 添加分页拦截器interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; }
}

4.2 常用功能介绍

1. CRUD 操作

MyBatis Plus 提供了基础的 CRUD 方法,包括 insertdeleteupdateselect 等。

    @Testvoid testInsert() {User user = User.builder().name("fengzhu").age(18).email("abc@a.com").build();userMapper.insert(user);}@Testvoid testSelect() {User user = userMapper.selectById(24L);System.out.println(user.getName());}@Testvoid testUpdate() {User user = User.builder().id(27L).email("fasfas@a.com").build();int count = userMapper.updateById(user);System.out.println("update success:" + count);}@Testvoid testDelete() {userMapper.deleteById(24L);}

2. 条件构造器

条件构造器主要涉及到3个类,AbstractWrapperQueryWrapperUpdateWrapper

在AbstractWrapper中提供了非常多的方法用于构建WHERE条件,而QueryWrapper针对SELECT语句,提供了select()方法,可自定义需要查询的列,而UpdateWrapper针对UPDATE语句,提供了set()方法,用于构造set语句,条件构造器也支持lambda表达式。

AbstractWrapper中用于构建SQL语句中的WHERE条件的方法进行部分列举

  • eq:equals,等于
  • allEq:all equals,全等于
  • ne:not equals,不等于
  • gt:greater than ,大于 >
  • ge:greater than or equals,大于等于≥
  • lt:less than,小于<
  • le:less than or equals,小于等于≤
  • between:相当于SQL中的BETWEEN
  • notBetween
  • like:模糊匹配。like(“name”,“黄”),相当于SQL的name like ‘%黄%’
  • likeRight:模糊匹配右半边。likeRight(“name”,“黄”),相当于SQL的name like ‘黄%’
  • likeLeft:模糊匹配左半边。likeLeft(“name”,“黄”),相当于SQL的name like ‘%黄’
  • notLike:notLike(“name”,“黄”),相当于SQL的name not like ‘%黄%’
  • isNull
  • isNotNull
  • in
  • and:SQL连接符AND
  • or:SQL连接符OR
  • apply:用于拼接SQL,该方法可用于数据库函数,并可以动态传参
// 条件查询
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "Tom");
List<User> users = userMapper.selectList(queryWrapper);// 条件更新
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", "Tom").set("age", 27);
userMapper.update(updateWrapper);

3. Condition

条件构造器的诸多方法中,均可以指定一个boolean类型的参数condition,用来决定该条件是否加入最后生成的WHERE语句中,比如

String name = "黄"; // 假设name变量是一个外部传入的参数
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.hasText(name), "name", name);
// 仅当 StringUtils.hasText(name) 为 true 时, 会拼接这个like语句到WHERE中
// 其实就是对下面代码的简化
if (StringUtils.hasText(name)) {wrapper.like("name", name);
}

4. 实体对象作为条件

调用构造函数创建一个Wrapper对象时,可以传入一个实体对象。后续使用这个Wrapper时,会以实体对象中的非空属性,构建WHERE条件(默认构建等值匹配的WHERE条件,这个行为可以通过实体类里各个字段上的@TableField注解中的condition属性进行改变)

@Test
public void test3() {User user = new User();user.setName("abc");user.setAge(28);QueryWrapper<User> wrapper = new QueryWrapper<>(user);List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}

5. allEq方法

  • allEq方法传入一个map,用来做等值匹配
  • 当allEq方法传入的Map中有value为null的元素时,默认会设置为is null
  • 若想忽略map中value为null的元素,可以在调用allEq时,设置参数boolean null2IsNull为false
@Test
public void test3() {QueryWrapper<User> wrapper = new QueryWrapper<>();Map<String, Object> param = new HashMap<>();param.put("age", 40);param.put("name", null);wrapper.allEq(param);List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}

6. lambda条件构造器

  • lambda条件构造器,支持lambda表达式,可以不必像普通条件构造器一样,以字符串形式指定列名,它可以直接以实体类的方法引用来指定列。
  • 像普通的条件构造器,列名是用字符串的形式指定,无法在编译期进行列名合法性的检查,这就不如lambda条件构造器来的优雅。
@Test
public void testLambda() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.like(User::getName, "黄").lt(User::getAge, 30);List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}- `like(User::getName, "黄")`:表示查询 `User` 表中 `name` 字段包含"黄"的记录。
- `lt(User::getAge, 30)`:表示查询 `User` 表中 `age` 字段小于 30 的记录
更新操作
  • updateById(T entity)
    根据入参entity的id(主键)进行更新,对于entity中非空的属性,会出现在UPDATE语句的SET后面,即entity中非空的属性,会被更新到数据库,示例如下
	@Testpublic void testUpdate2() {User user = new User();user.setId(1L); // 假设要更新的用户 IDuser.setName("新的名字"); // 只更新名字,其他属性保持不变userMapper.updateById(user);}
  • update(T entity, Wrapper<T> wrapper)
    根据实体entity和条件构造器wrapper进行更新,示例如下
	@Testpublic void testUpdate2() {User user = new User();user.setName("abc");LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.between(User::getAge, 26,31).likeRight(User::getName,"吴");userMapper.update(user, wrapper);}
删除操作

BaseMapper一共提供了如下几个用于删除的方法

  • deleteById 根据主键id进行删除
  • deleteBatchIds 根据主键id进行批量删除
  • deleteByMap 根据Map进行删除(Map中的key为列名,value为值,根据列和值进行等值匹配)
  • delete(Wrapper<T> wrapper) 根据条件构造器Wrapper进行删除

7. 自定义Sql

  • 注解
	@Select("select * from user")List<User> selectRaw();
  • xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mp.mappers.UserMapper"><select id="selectRaw" resultType="com.example.mp.po.User">SELECT * FROM user</select>
</mapper>public interface UserMapper extends BaseMapper<User> {List<User> selectRaw();
}

8. 分页插件

  • 配置分页插件,在 MybatisPlusConfig 类中添加分页插件配置。
    @Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbTypereturn interceptor;}
  • 在查询时使用 Page 对象进行分页。
    @Testpublic void testPage() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.ge(User::getAge, 28);// 设置分页信息, 查第3页, 每页2条数据Page<User> page = new Page<>(3, 2);// 执行分页查询Page<User> userPage = userMapper.selectPage(page, wrapper);System.out.println("总记录数 = " + userPage.getTotal());System.out.println("总页数 = " + userPage.getPages());System.out.println("当前页码 = " + userPage.getCurrent());// 获取分页查询结果List<User> records = userPage.getRecords();records.forEach(System.out::println);}

9. 代码生成器

  • MyBatis Plus 提供了代码生成器,可以根据数据库表自动生成实体类、Mapper 接口、Service 类和 Controller 类。
public class Generator {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8","root", "").globalConfig(builder -> builder.author("aa").outputDir("your-path")).packageConfig(builder -> builder.parent("your-package").entity("entity").mapper("mapper").service("service").serviceImpl("service.impl").xml("mapper.xml")).strategyConfig(builder -> builder.entityBuilder().enableLombok()).templateEngine(new FreemarkerTemplateEngine()).execute();}
}

4.3 高级功能

1. 自动填充

通过在实体类里面的字段进行设置时间戳, create_time, update_time等字段需要自动填充

	@TableField(fill = FieldFill.INSERT) // 插入时自动填充private long createTime;@TableField(fill = FieldFill.INSERT_UPDATE) // 插入/更新时自动填充private long updateTime;

自定义类 MetaObjectHandler 实现 MetaObjectHandler接口,并且去重写其两个方法:

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {log.info("开始插入填充...");this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());}@Overridepublic void updateFill(MetaObject metaObject) {log.info("开始更新填充...");this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}
}

2. 乐观锁(并发的情况)

乐观锁是一种并发控制机制,用于确保在更新记录时,该记录未被其他事务修改。MyBatis-Plus 提供了 OptimisticLockerInnerInterceptor 插件,使得在应用中实现乐观锁变得简单。

乐观锁的实现原理包括以下步骤:

  1. 读取记录时,获取当前的版本号(version)。
  2. 在更新记录时,将这个版本号一同传递。
  3. 执行更新操作时,设置 version = newVersion 的条件为 version = oldVersion。
  4. 如果版本号不匹配,则更新失败。

配置乐观锁插件:

    @Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}

Entity对象version字段加上@version注解

import com.baomidou.mybatisplus.annotation.Version;@Data
public class User {@TableIdprivate Long id;private String name;private Integer age;private String email;@Versionprivate Integer version;
}

相关文章:

Spring boot 知识整理

一、SpringBoot 背景内容梳理 SpringBoot是一个基于Spring框架的开源框架&#xff0c;用于简化Spring应用程序的初始搭建和开发过程。它通过提供约定优于配置的方式&#xff0c;尽可能减少开发者的工作量&#xff0c;使得开发Spring应用变得更加快速、便捷和高效。 SpringBoot…...

transformer 规范化层

目标 了解规范化层的作用掌握规范化层的实现过程 作用 所有的深层网络模型都需要标准网络层, 因为随着网络层数量的增加, 通过多层的计算后参数可能出现过大或者过小的情况, 这样可能导致在学习过程出现异常, 模型可能收敛比较慢,因此都会在一定的层数后接规范化层进行数值的…...

RCL谐振电压增益曲线

谐振电路如何通过调频实现稳压&#xff1f; 为什么要做谐振&#xff1f; 在谐振状态实现ZVS导通&#xff0c;小电流关断 电压增益GVo/Vin&#xff0c;相当于产出投入比 当ff0时&#xff0c;G1时&#xff0c;输出电压输入电压 当G<1时&#xff0c;输出电压<输入电压 …...

JavaScript:表单及正则表达式验证

今天我要介绍的是在JavaScript中关于表单验证内容的知识点介绍&#xff1a; 关于表单验证&#xff0c;我接下来则直接将内容以及效果显示出来并作注解&#xff0c;这样可以清晰看见这个表达验证的妙用&#xff1a; <form id"ff" action"https://www.baidu.…...

一、Appium环境安装

找了一圈操作手机的工具或软件&#xff0c;踩了好多坑&#xff0c;最后决定用这个工具(影刀RPA手机用的也是这个)&#xff0c;目前最新的版本是v2.17.1&#xff0c;是基于nodejs环境的&#xff0c;有两种方式&#xff0c;我只试了第一种方式&#xff0c;第二种方式应该是比较简…...

精益数据分析(3/126):用数据驱动企业发展的深度解析

精益数据分析&#xff08;3/126&#xff09;&#xff1a;用数据驱动企业发展的深度解析 大家好&#xff01;一直以来&#xff0c;我都坚信在当今竞争激烈的商业环境中&#xff0c;数据是企业获得竞争优势的关键。最近深入研究《精益数据分析》这本书&#xff0c;收获颇丰&…...

暂存一下等会写

#include<easyx.h> IMAGE SNOW 图形变量 struct MOVE生存结构体 {int x0;int y0; bool livefalse;}; initgraph(800, 800);初始化图形界面 MOVE snowflake[5000];目标数量 loadimage(&SNOW, "snow.png");加载图片 BeginBatchDraw(); 开始批量绘图。…...

【c++深入系列】:new和delete运算符详解

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; “生活不会向你许诺什么&#xff0c;尤其不会向你许诺成功。它只会给你挣扎、痛苦和煎熬的过程。但只要你坚持下去&#xff0c;终有一天&…...

正弦波有效值和平均值(学习笔记)

一个周期的正弦波在坐标轴上围的面积有多大&#xff1f; 一般正弦波以 y Asin(wx)表示&#xff0c;其中A为振幅&#xff0c;W为角速度。周期T 2π/w; 确定积分区间是x 0&#xff0c;到x 2π。 计算绝对值积分&#xff1a; 变量代还&#xff1a;wx θ&#xff0c;dx dθ…...

《分布式软总线架构下,设备虚拟化技术的深度剖析与优化策略》

设备之间的互联互通和协同工作已成为一种趋势。分布式软总线架构作为实现这一目标的关键技术&#xff0c;为不同设备之间的通信和协作提供了基础。而设备虚拟化技术则是在分布式软总线架构下&#xff0c;进一步提升设备资源利用效率的重要手段。本文将深入探讨在分布式软总线架…...

首次打蓝桥杯总结(c/c++B组)

目录 一、对每个题进行总结 1.填空题 2.第一个大题---可分解的正整数&#xff08;10--3&#xff09; 3.第二道大题---产值调整&#xff08;10--3&#xff09; 4.第三道大题---画展部署&#xff08;15--7&#xff09; 5.第四道大题---水质检测&#xff08;15--3&#x…...

第八天 开始Unity Shader的学习之Blinn-Phong光照模型

Unity Shader的学习笔记 第八天 开始Unity Shader的学习之Blinn-Phong光照模型 文章目录 Unity Shader的学习笔记前言一、Blinn-Phong光照模型①计算高光反射部分效果展示 二、召唤神龙:使用Unity内置的函数总结 前言 今天我们编写另一种高光反射的实现方法 – Blinn光照模型…...

游戏NPC对话AI生成的管理调用系统设计

系统概述 游戏与故事人物对话模拟系统 此系统旨在模拟游戏或故事场景里人物的对话。它具备创建游戏与人物信息的功能&#xff0c;并且能借助输入游戏、人物、时间、地点、场景等信息&#xff0c;调用 OpenAI 格式的接口(通过One Api支持DeepSeek之类的其他AI)得到人物的对话内容…...

Go:使用共享变量实现并发

竞态 在串行程序中&#xff0c;步骤执行顺序由程序逻辑决定&#xff1b;而在有多个 goroutine 的并发程序中&#xff0c;不同 goroutine 的事件先后顺序不确定&#xff0c;若无法确定两个事件先后&#xff0c;它们就是并发的。若一个函数在并发调用时能正确工作&#xff0c;称…...

豆瓣图书数据采集与可视化分析

文章目录 一、适用题目二、豆瓣图书数据采集1. 图书分类采集2. 爬取不同分类的图书数据3. 各个分类数据整合 三、豆瓣图书数据清洗四、数据分析五、数据可视化1. 数据可视化大屏展示 源码获取看下方名片 一、适用题目 基于Python的豆瓣图书数据采集与分析基于Python的豆瓣图书…...

常见的爬虫算法

1.base64加密 base64是什么 Base64编码&#xff0c;是由64个字符组成编码集&#xff1a;26个大写字母AZ&#xff0c;26个小写字母az&#xff0c;10个数字0~9&#xff0c;符号“”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节&#xff0c;然后…...

Numpy常用库方法总结

numpy的底层是ndarray&#xff0c;也就是矩阵结构 对于ndarray结构来说&#xff0c;里面所有的元素必须是同一类型的 如果不是的话&#xff0c;会自动的向下进行转换 list [1,2,3,4,5] array np.array(list) array输出&#xff1a;array([1, 2, 3, 4, 5]) 1.1 ndarray基本…...

YOLOV8 OBB 海思3516训练流程

YOLOV8 OBB 海思3516训练流程 目录 1、 下载带GPU版本的torch(可选) 1 2、 安装 ultralytics 2 3、 下载pycharm 社区版 2 4、安装pycharm 3 5、新建pycharm 工程 3 6、 添加conda 环境 4 7、 训练代码 5 9、配置Ymal 文件 6 10、修改网络结构 9 11、运行train.py 开始训练模…...

[MySQL] 事务管理(二) 事务的隔离性底层

事务的隔离性底层 1.数据库并发的场景2.读-写2.1MVCC三个变量2.1.1 3个记录隐藏列字段2.1.2 undo日志 模拟MVCCselect 的读取2.1.3 Read View&#xff08;读视图&#xff09; 3.RR与RC的区别 1.数据库并发的场景 读-读&#xff1a;不存在问题&#xff0c;也不需要并发控制读-写…...

20、.NET SDK概述

.NET SDK&#xff08;Software Development Kit&#xff09; 是微软提供的一套开发工具包&#xff0c;用于构建、运行和管理基于 .NET 平台的应用程序。它包含了一组丰富的工具、库和运行时环境&#xff0c;支持开发者在多种操作系统&#xff08;如 Windows、Linux 和 macOS&am…...

Go:包和 go 工具

引言 通过对关联特性分类&#xff0c;组成便于理解和修改的单元&#xff0c;使包与程序其他包保持独立&#xff0c;助力大型程序的设计与维护 。模块化让包可在不同项目共享、复用、发布及全球范围使用。 每个包定义不同命名空间作为标识符&#xff0c;关联具体包&#xff0c…...

18-21源码剖析——Mybatis整体架构设计、核心组件调用关系、源码环境搭建

学习视频资料来源&#xff1a;https://www.bilibili.com/video/BV1R14y1W7yS 文章目录 1. 架构设计2. 核心组件及调用关系3. 源码环境搭建3.1 测试类3.2 实体类3.3 核心配置文件3.4 映射配置文件3.5 遇到的问题 1. 架构设计 Mybatis整体架构分为4层&#xff1a; 接口层&#…...

冒泡排序、插入排序、快速排序、堆排序、希尔排序、归并排序

目录 冒泡排序插入排序快速排序(未优化版本)快速排序(优化版本)堆排序希尔排序归并排序各排序时间消耗对比 冒泡排序 冒泡排序核心逻辑就是对数组从第一个位置开始进行遍历&#xff0c;如果发现该元素比下一个元素大&#xff0c;则交换位置&#xff0c;如果不大&#xff0c;就…...

Docker Compose 中配置 Host 网络模式

在 Docker Compose 中配置 Host 网络模式时&#xff0c;需通过 network_mode 参数直接指定容器使用宿主机的网络栈。以下是具体配置方法及注意事项&#xff1a; 1. 基础配置示例 在 docker-compose.yml 文件中&#xff0c;为需要启用 Host 模式的服务添加 network_mode: "…...

HTML、CSS 和 JavaScript 常见用法及使用规范

一、HTML 深度剖析 1. 文档类型声明 HTML 文档开头的 <!DOCTYPE html> 声明告知浏览器当前文档使用的是 HTML5 标准。它是文档的重要元信息&#xff0c;能确保浏览器以标准模式渲染页面&#xff0c;避免怪异模式下的兼容性问题。 2. 元数据标签 <meta> 标签&am…...

Elasticsearch 索引数据量激增的应对与优化:从原理到部署实践

Elasticsearch&#xff08;ES&#xff09;作为一款强大的分布式搜索和分析引擎&#xff0c;广泛应用于日志分析、全文搜索和实时数据处理等场景。然而&#xff0c;随着数据量激增&#xff0c;索引可能面临性能瓶颈&#xff0c;如写入变慢、查询延迟高或存储成本上升。如何有效应…...

CD27.【C++ Dev】类和对象 (18)友元和内部类

目录 1.友元 友元函数 几个特点 友元类 格式 代码示例 2.内部类(了解即可) 计算有内部类的类的大小 分析 注意:内部类不能直接定义 内部类是外部类的友元类 3.练习 承接CD21.【C Dev】类和对象(12) 流插入运算符的重载文章 1.友元 友元函数 在CD21.【C Dev】类和…...

QT安装详细步骤

下载 清华源 &#xff1a; 清华源 1. 2. 3. 4....

Unity游戏多语言工具包

由于一开始的代码没有考虑多语言场景&#xff0c;导致代码中提示框和UI显示直接用了中文&#xff0c;最近开始提取代码的中文&#xff0c;提取起来太麻烦&#xff0c;所以拓展了之前的多语言包&#xff0c;降低了操作复杂度。最后把工具代码提取出来到单独项目里面&#xff0c;…...

实验三 I/O地址译码

一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示&#xff0c;其中74LS74为D触发器&#xff0c;可直接使用实验台上数字电路实验区的D触发器&#xff0c;74LS138为地址译码器&#xff0c; Y0&#xff1a;280H&#xff5e;287H&…...