Spring boot 知识整理
一、SpringBoot 背景内容梳理
-
SpringBoot是一个基于Spring框架的开源框架,用于简化Spring应用程序的初始搭建和开发过程。它通过提供约定优于配置的方式,尽可能减少开发者的工作量,使得开发Spring应用变得更加快速、便捷和高效。
-
SpringBoot的主要特点包括:
- 简化配置:SpringBoot遵循约定优于配置的原则,减少了传统Spring应用中的大量配置。它通过自动配置(auto-configuration)和起步依赖(starterdependencies)来简化项目的配置过程,让开发者可以快速搭建起一个可运行的Spring应用。
- 集成性强:SpringBoot提供了大量的开箱即用的特性和功能,如内嵌的Servlet容器(如Tomcat、Jetty或Undertow)、健康检查、指标监控等。它还整合了诸多常用的库和框架,如SpringData、SpringSecurity等,使得开发者可以快速构建出功能完善的应用。
- 微服务支持:SpringBoot非常适合用于构建微服务架构。它提供了丰富的支持,如通过SpringCloud进行微服务架构的开发,集成了服务发现、配置中心、负载均衡等功能,帮助开发者构建可伸缩、高可用的微服务系统。
- 内嵌服务器:SpringBoot可以将应用程序打包成一个可执行的JAR文件,并内置了常用的Servlet容器,如Tomcat、Jetty或Undertow。这样一来,开发者可以通过简单的java-jar命令来运行应用程序,而无需部署到外部应用服务器。
- 生态丰富:由于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):查找年龄在min和max之间的学生。findByNameStartingWith(String namePrefix):查找姓名以namePrefix开头的学生。
- 使用
@Query注解:- 可以使用
@Query注解来定义自定义查询。 - 原始 SQL 查询:
- 使用
nativeQuery = true指定这是一个原始 SQL 查询。 - 示例:
- 使用
- 可以使用
- 基本 CRUD 操作:
@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 方法,包括 insert、delete、update、select 等。
@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个类,AbstractWrapper,QueryWrapper,UpdateWrapper
在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 插件,使得在应用中实现乐观锁变得简单。
乐观锁的实现原理包括以下步骤:
- 读取记录时,获取当前的版本号(version)。
- 在更新记录时,将这个版本号一同传递。
- 执行更新操作时,设置 version = newVersion 的条件为 version = oldVersion。
- 如果版本号不匹配,则更新失败。
配置乐观锁插件:
@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框架的开源框架,用于简化Spring应用程序的初始搭建和开发过程。它通过提供约定优于配置的方式,尽可能减少开发者的工作量,使得开发Spring应用变得更加快速、便捷和高效。 SpringBoot…...
transformer 规范化层
目标 了解规范化层的作用掌握规范化层的实现过程 作用 所有的深层网络模型都需要标准网络层, 因为随着网络层数量的增加, 通过多层的计算后参数可能出现过大或者过小的情况, 这样可能导致在学习过程出现异常, 模型可能收敛比较慢,因此都会在一定的层数后接规范化层进行数值的…...
RCL谐振电压增益曲线
谐振电路如何通过调频实现稳压? 为什么要做谐振? 在谐振状态实现ZVS导通,小电流关断 电压增益GVo/Vin,相当于产出投入比 当ff0时,G1时,输出电压输入电压 当G<1时,输出电压<输入电压 …...
JavaScript:表单及正则表达式验证
今天我要介绍的是在JavaScript中关于表单验证内容的知识点介绍: 关于表单验证,我接下来则直接将内容以及效果显示出来并作注解,这样可以清晰看见这个表达验证的妙用: <form id"ff" action"https://www.baidu.…...
一、Appium环境安装
找了一圈操作手机的工具或软件,踩了好多坑,最后决定用这个工具(影刀RPA手机用的也是这个),目前最新的版本是v2.17.1,是基于nodejs环境的,有两种方式,我只试了第一种方式,第二种方式应该是比较简…...
精益数据分析(3/126):用数据驱动企业发展的深度解析
精益数据分析(3/126):用数据驱动企业发展的深度解析 大家好!一直以来,我都坚信在当今竞争激烈的商业环境中,数据是企业获得竞争优势的关键。最近深入研究《精益数据分析》这本书,收获颇丰&…...
暂存一下等会写
#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运算符详解
🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: “生活不会向你许诺什么,尤其不会向你许诺成功。它只会给你挣扎、痛苦和煎熬的过程。但只要你坚持下去,终有一天&…...
正弦波有效值和平均值(学习笔记)
一个周期的正弦波在坐标轴上围的面积有多大? 一般正弦波以 y Asin(wx)表示,其中A为振幅,W为角速度。周期T 2π/w; 确定积分区间是x 0,到x 2π。 计算绝对值积分: 变量代还:wx θ,dx dθ…...
《分布式软总线架构下,设备虚拟化技术的深度剖析与优化策略》
设备之间的互联互通和协同工作已成为一种趋势。分布式软总线架构作为实现这一目标的关键技术,为不同设备之间的通信和协作提供了基础。而设备虚拟化技术则是在分布式软总线架构下,进一步提升设备资源利用效率的重要手段。本文将深入探讨在分布式软总线架…...
首次打蓝桥杯总结(c/c++B组)
目录 一、对每个题进行总结 1.填空题 2.第一个大题---可分解的正整数(10--3) 3.第二道大题---产值调整(10--3) 4.第三道大题---画展部署(15--7) 5.第四道大题---水质检测(15--3&#x…...
第八天 开始Unity Shader的学习之Blinn-Phong光照模型
Unity Shader的学习笔记 第八天 开始Unity Shader的学习之Blinn-Phong光照模型 文章目录 Unity Shader的学习笔记前言一、Blinn-Phong光照模型①计算高光反射部分效果展示 二、召唤神龙:使用Unity内置的函数总结 前言 今天我们编写另一种高光反射的实现方法 – Blinn光照模型…...
游戏NPC对话AI生成的管理调用系统设计
系统概述 游戏与故事人物对话模拟系统 此系统旨在模拟游戏或故事场景里人物的对话。它具备创建游戏与人物信息的功能,并且能借助输入游戏、人物、时间、地点、场景等信息,调用 OpenAI 格式的接口(通过One Api支持DeepSeek之类的其他AI)得到人物的对话内容…...
Go:使用共享变量实现并发
竞态 在串行程序中,步骤执行顺序由程序逻辑决定;而在有多个 goroutine 的并发程序中,不同 goroutine 的事件先后顺序不确定,若无法确定两个事件先后,它们就是并发的。若一个函数在并发调用时能正确工作,称…...
豆瓣图书数据采集与可视化分析
文章目录 一、适用题目二、豆瓣图书数据采集1. 图书分类采集2. 爬取不同分类的图书数据3. 各个分类数据整合 三、豆瓣图书数据清洗四、数据分析五、数据可视化1. 数据可视化大屏展示 源码获取看下方名片 一、适用题目 基于Python的豆瓣图书数据采集与分析基于Python的豆瓣图书…...
常见的爬虫算法
1.base64加密 base64是什么 Base64编码,是由64个字符组成编码集:26个大写字母AZ,26个小写字母az,10个数字0~9,符号“”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节,然后…...
Numpy常用库方法总结
numpy的底层是ndarray,也就是矩阵结构 对于ndarray结构来说,里面所有的元素必须是同一类型的 如果不是的话,会自动的向下进行转换 list [1,2,3,4,5] array np.array(list) array输出: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(读视图) 3.RR与RC的区别 1.数据库并发的场景 读-读:不存在问题,也不需要并发控制读-写…...
20、.NET SDK概述
.NET SDK(Software Development Kit) 是微软提供的一套开发工具包,用于构建、运行和管理基于 .NET 平台的应用程序。它包含了一组丰富的工具、库和运行时环境,支持开发者在多种操作系统(如 Windows、Linux 和 macOS&am…...
Go:包和 go 工具
引言 通过对关联特性分类,组成便于理解和修改的单元,使包与程序其他包保持独立,助力大型程序的设计与维护 。模块化让包可在不同项目共享、复用、发布及全球范围使用。 每个包定义不同命名空间作为标识符,关联具体包,…...
18-21源码剖析——Mybatis整体架构设计、核心组件调用关系、源码环境搭建
学习视频资料来源:https://www.bilibili.com/video/BV1R14y1W7yS 文章目录 1. 架构设计2. 核心组件及调用关系3. 源码环境搭建3.1 测试类3.2 实体类3.3 核心配置文件3.4 映射配置文件3.5 遇到的问题 1. 架构设计 Mybatis整体架构分为4层: 接口层&#…...
冒泡排序、插入排序、快速排序、堆排序、希尔排序、归并排序
目录 冒泡排序插入排序快速排序(未优化版本)快速排序(优化版本)堆排序希尔排序归并排序各排序时间消耗对比 冒泡排序 冒泡排序核心逻辑就是对数组从第一个位置开始进行遍历,如果发现该元素比下一个元素大,则交换位置,如果不大,就…...
Docker Compose 中配置 Host 网络模式
在 Docker Compose 中配置 Host 网络模式时,需通过 network_mode 参数直接指定容器使用宿主机的网络栈。以下是具体配置方法及注意事项: 1. 基础配置示例 在 docker-compose.yml 文件中,为需要启用 Host 模式的服务添加 network_mode: "…...
HTML、CSS 和 JavaScript 常见用法及使用规范
一、HTML 深度剖析 1. 文档类型声明 HTML 文档开头的 <!DOCTYPE html> 声明告知浏览器当前文档使用的是 HTML5 标准。它是文档的重要元信息,能确保浏览器以标准模式渲染页面,避免怪异模式下的兼容性问题。 2. 元数据标签 <meta> 标签&am…...
Elasticsearch 索引数据量激增的应对与优化:从原理到部署实践
Elasticsearch(ES)作为一款强大的分布式搜索和分析引擎,广泛应用于日志分析、全文搜索和实时数据处理等场景。然而,随着数据量激增,索引可能面临性能瓶颈,如写入变慢、查询延迟高或存储成本上升。如何有效应…...
CD27.【C++ Dev】类和对象 (18)友元和内部类
目录 1.友元 友元函数 几个特点 友元类 格式 代码示例 2.内部类(了解即可) 计算有内部类的类的大小 分析 注意:内部类不能直接定义 内部类是外部类的友元类 3.练习 承接CD21.【C Dev】类和对象(12) 流插入运算符的重载文章 1.友元 友元函数 在CD21.【C Dev】类和…...
QT安装详细步骤
下载 清华源 : 清华源 1. 2. 3. 4....
Unity游戏多语言工具包
由于一开始的代码没有考虑多语言场景,导致代码中提示框和UI显示直接用了中文,最近开始提取代码的中文,提取起来太麻烦,所以拓展了之前的多语言包,降低了操作复杂度。最后把工具代码提取出来到单独项目里面,…...
实验三 I/O地址译码
一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示,其中74LS74为D触发器,可直接使用实验台上数字电路实验区的D触发器,74LS138为地址译码器, Y0:280H~287H&…...
