解决几个常见的ASP.NET Core Web API 中多线程并发写入数据库失败的问题
前言
在ASP.NET Core Web API应用程序中,当多个并发线程同时调用新增用户数据的接口时,可能会遇到数据库写入失败的问题。这个问题通常源于多个线程同时访问数据库时,可能会导致以下情况:
- 数据库连接池耗尽:每个线程都可能创建一个数据库连接,如果并发量过大,可能会导致数据库连接池用尽,从而无法创建新的连接,导致写入失败。
- 数据一致性问题:多个线程同时写入数据库时,可能会造成数据冲突或违反唯一性约束。
- 事务问题:没有适当的事务控制,多个线程可能在执行写入时发生数据不一致或冲突。
接下来,我们将通过示例来说明如何解决这些问题。
示例:多线程并发写入数据库
为了完整地实现一个基于 ASP.NET Core Web API 的应用,使用 MySQL 数据库并处理多线程并发写入的问题,以下是一个完整的示例代码,包括了 Program.cs
中的服务注册、MySQL 配置以及其它相关的服务和依赖注入设置。
1. 配置数据库连接和服务注册
首先,确保的 appsettings.json
中包含 MySQL 的连接字符串配置:
1.1 appsettings.json
{"ConnectionStrings": {"DefaultConnection": "Server=localhost;Database=usersdb;User=root;Password=root;"},"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*"
}
这个配置中的 DefaultConnection
是 MySQL 的连接字符串,确保替换为MySQL 数据库的实际连接信息。
2. 配置数据库上下文
需要使用 Entity Framework Core 来访问 MySQL 数据库,首先在 Program.cs
中注册数据库上下文。
2.1 安装 NuGet 包
在项目中安装必要的 NuGet 包,包括 Pomelo.EntityFrameworkCore.MySql
(用于支持 MySQL)和 Microsoft.EntityFrameworkCore
:
<ItemGroup><PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" /><PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.11" /><PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.11" /><PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference><PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.11" /><PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.11"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference><PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /><PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /></ItemGroup>
2.2 配置数据库上下文
在 Program.cs
中进行数据库配置,确保将 MySQL 服务注册到依赖注入容器中。
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sample1215.Models;
using Sample1215.Repositories;var builder = WebApplication.CreateBuilder(args);// 1. 注册数据库上下文服务
builder.Services.AddDbContext<ApplicationDbContext>(options =>options.UseMySql(builder.Configuration.GetConnectionString("DefaultConnection"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("DefaultConnection"))));// 2. 注册自定义服务
builder.Services.AddScoped<IUserRepository, UserRepository>();// 3. 注册控制器服务
builder.Services.AddControllers();// 4. 注册Swagger(可选,用于API文档)
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();var app = builder.Build();// 5. 配置中间件
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseAuthorization();
app.MapControllers();app.Run();
在上述代码中,我们执行了以下操作:
- 通过
builder.Services.AddDbContext<ApplicationDbContext>
注册了数据库上下文,配置了 MySQL 数据库连接字符串。 - 注册了
IUserRepository
接口和UserRepository
实现,确保服务可以通过依赖注入使用。 - 配置了Swagger(可选),以便在开发环境下自动生成API文档。
3. 创建数据库上下文和实体类
3.1 ApplicationDbContext.cs
这是数据库上下文类,继承自 DbContext
,用于与 MySQL 进行交互。
using Microsoft.EntityFrameworkCore;namespace Sample1215.Models
{public class ApplicationDbContext : DbContext{public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options){ }public DbSet<User> Users { get; set; }}
}
3.2 User.cs
实体类
这是 User
实体类,表示数据库中的用户表。
namespace Sample1215.Models
{public class User{public int Id { get; set; }public string Name { get; set; }public string Email { get; set; }}
}
4. 创建 UserRepository
实现
4.1 IUserRepository.cs
这是用户数据存储接口。
namespace Sample1215.Repositories
{public interface IUserRepository{Task AddUserAsync(User user);}
}
4.2 UserRepository.cs
这是 UserRepository
类的实现,负责将数据插入 MySQL 数据库。第一版我们这么实现
public class UserRepository : IUserRepository
{private readonly ApplicationDbContext _context;public UserRepository(ApplicationDbContext context){_context = context;}public async Task AddUserAsync(User user){// 模拟并发场景await _context.Users.AddAsync(user);await _context.SaveChangesAsync(); // 写入数据库}
}
5. 完整的 API 控制器
5.1 UsersController.cs
这是 API 控制器,负责处理用户新增请求。第一版我们这么实现。
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{private readonly IUserRepository _userRepository;public UsersController(IUserRepository userRepository){_userRepository = userRepository;}[HttpPost]public async Task<IActionResult> CreateUserAsync([FromBody] User user){if (user == null){return BadRequest("Invalid user data.");}try{await _userRepository.AddUserAsync(user);return Ok("User created successfully.");}catch (Exception ex){return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);}}
}
6. 启动和迁移数据库
6.1 在终端运行迁移命令
确保已为 ApplicationDbContext
添加了迁移并更新了数据库。在终端中运行以下命令:
dotnet ef migrations add InitialCreate
dotnet ef database update
执行完毕之后
这些命令将为的 MySQL 数据库创建初始的 Users
表,并将其同步到数据库中。
测试验证问题:并发写入导致失败
为了测试并发请求在 Web API 中的处理,我们可以使用单元测试框架来模拟多个并发请求。这里我们将使用 xUnit
作为单元测试框架,并使用 Microsoft.AspNetCore.Mvc.Testing
和 HttpClient
来模拟 HTTP 请求。
1. 添加所需的 NuGet 包
在测试项目中,确保添加以下 NuGet 包:
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>disable</Nullable><IsPackable>false</IsPackable><IsTestProject>true</IsTestProject></PropertyGroup><ItemGroup><PackageReference Include="coverlet.collector" Version="6.0.0" /><PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.11" /><PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" /><PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" /><PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /><PackageReference Include="Moq" Version="4.20.72" /><PackageReference Include="xunit" Version="2.9.2" /><PackageReference Include="xunit.runner.visualstudio" Version="2.8.2"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference></ItemGroup><ItemGroup><ProjectReference Include="..\Sample1215\Sample1215.csproj" /></ItemGroup><ItemGroup><Using Include="Xunit" /></ItemGroup></Project>
这些包将帮助我们执行 Web API 测试,模拟数据库操作,并进行并发请求测试。
2. 创建测试项目
我们的Web API 项目名称为 Sample1215
,然后我们就创建一个名为 Sample1215.Test
的测试项目。在此项目中,我们将编写针对 Web API 的单元测试代码。
3. 编写并发测试代码
我们将使用 xUnit
来编写并发请求的单元测试。这个测试将模拟多个线程同时调用 CreateUserAsync
API。
3.1 ConcurrencyTest.cs
创建一个 ConcurrencyTest.cs
文件来编写测试代码。
using Microsoft.AspNetCore.Mvc.Testing;
using Sample1215.Model;
using System.Net.Http.Json;namespace Sample1215.Tests
{public class ConcurrencyTest : IClassFixture<WebApplicationFactory<Program>>{private readonly WebApplicationFactory<Program> _factory;public ConcurrencyTest(WebApplicationFactory<Program> factory){_factory = factory;}[Fact]public async Task CreateUser_ConcurrentRequests_ShouldBeHandledCorrectly(){// Arrangevar client = _factory.CreateClient();var user = new User{Name = "Test User",Email = "testuser@example.com"};// 通过多个并发请求模拟并发写入var tasks = new Task[20000]; // 模拟20000个并发请求for (int i = 0; i < tasks.Length; i++){tasks[i] = SendPostRequest(client, user);}// Actawait Task.WhenAll(tasks);// Assert// 你可以通过检查数据库中的记录数或检查响应状态来确保请求成功// 比如,检查某个唯一标识符是否插入成功,或者返回的状态码是否都为200// 例如,检查每个请求的状态码是否都是200foreach (var task in tasks){Assert.True(task.IsCompletedSuccessfully);}}private async Task SendPostRequest(HttpClient client, User user){var response = await client.PostAsJsonAsync("/api/users", user);response.EnsureSuccessStatusCode(); // 确保请求成功}}
}
4. 解释测试代码
WebApplicationFactory<Program>
:这是一个Microsoft.AspNetCore.Mvc.Testing
提供的工厂类,它允许我们在测试环境中启动 Web API,并创建 HTTP 客户端。SendPostRequest
:这个辅助方法负责向 Web API 发送POST
请求,将用户数据提交到/api/users
。- 并发请求:我们使用
Task.WhenAll
来等待多个并发请求同时执行,这模拟了多个线程同时访问 Web API 的场景。 Assert
:在测试完成后,我们验证所有请求是否成功完成,确保所有并发请求都能被正确处理。
5. 数据库模拟
为了测试并发请求,我们使用了 InMemory
数据库来避免在真实 MySQL 数据库中进行操作。这样,所有的测试都可以在内存中完成,而不影响实际的数据库。
5.1 配置 InMemory 数据库
在 Program.cs
文件中,我们可以在测试中使用 InMemory
数据库,以便进行更快、更隔离的单元测试。可以将数据库上下文注册到 InMemory
提供程序中。
修改 Program.cs
中的数据库注册部分,如下所示:
// 在测试环境中使用InMemory数据库
builder.Services.AddDbContext<ApplicationDbContext>(options =>options.UseInMemoryDatabase("TestDatabase")); // 使用InMemory数据库
6. 运行测试
现在,我们已经创建了一个并发测试,用于验证在 Web API 中并发请求的处理是否正确。在命令行中运行以下命令来执行单元测试:
dotnet test
7. 测试总结
我们已经实现了一个针对 POST /api/users
接口的并发请求单元测试。通过使用 xUnit
和 WebApplicationFactory
,我们可以模拟多并发请求并测试 API 在高并发场景下的稳定性。此外,使用 InMemory
数据库让我们能够快速进行测试而无需连接到真实数据库,这为开发和调试提供了便利。
在这个简单的例子中,假设API接口被多个并发线程调用。每个请求都会创建一个新的User
并调用AddUserAsync
方法将其插入到数据库中。如果并发线程过多,以下问题可能会发生:
- 数据库连接池耗尽:每个线程都需要获取数据库连接,若并发量过大,可能导致连接池用尽。
- 唯一性冲突:如果并发插入的用户具有相同的唯一约束(如
Email
),可能会出现违反唯一性约束的错误。 - 事务冲突:多个线程可能会同时修改相同的数据,导致事务失败。
500异常
和断言异常
解决方案
1. 使用数据库事务保证一致性
为了保证多个并发线程插入数据库时的一致性,可以使用数据库事务来确保每个写入操作都是原子的。如果有多个写入操作失败,则可以回滚事务。
public class UserRepository : IUserRepository
{private readonly ApplicationDbContext _context;public UserRepository(ApplicationDbContext context){_context = context;}public async Task AddUserAsync(User user){// 使用数据库事务using (var transaction = await _context.Database.BeginTransactionAsync()){try{await _context.Users.AddAsync(user);await _context.SaveChangesAsync();// 提交事务await transaction.CommitAsync();}catch (Exception){// 回滚事务await transaction.RollbackAsync();throw;}}}
}
2. 限制并发请求
为了避免数据库连接池耗尽,可以限制API的并发请求数。我们可以通过使用SemaphoreSlim
来控制并发线程的数量。
using Microsoft.AspNetCore.Mvc;
using Sample1215.Models;
using Sample1215.Repositories;namespace Sample1215.Controllers
{[ApiController][Route("api/[controller]")]public class UsersController : ControllerBase{private static SemaphoreSlim _semaphore = new SemaphoreSlim(10); // 限制最大并发10个请求private readonly IUserRepository _userRepository;public UsersController(IUserRepository userRepository){_userRepository = userRepository;}[HttpPost]public async Task<IActionResult> CreateUserAsync([FromBody] User user){if (user == null){return BadRequest("Invalid user data.");}// 等待直到有空闲的线程await _semaphore.WaitAsync();try{await _userRepository.AddUserAsync(user);return Ok("User created successfully.");}catch (Exception ex){return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);}finally{// 完成后释放信号量_semaphore.Release();}}}
}
这样,最多只有10个线程可以同时写入数据库。如果更多请求到达,后续的请求会等待直到前面的请求完成。
3. 使用乐观锁解决数据冲突
如果并发写入的用户数据存在唯一性约束(例如Email
),我们可以在数据库中使用乐观锁或在业务逻辑中检查唯一性。假设用户的Email
字段是唯一的,插入数据之前,可以先检查数据库中是否已经存在相同的Email
。
public class UserRepository : IUserRepository
{private readonly ApplicationDbContext _context;public UserRepository(ApplicationDbContext context){_context = context;}public async Task AddUserAsync(User user){// 检查Email是否已存在var existingUser = await _context.Users.FirstOrDefaultAsync(u => u.Email == user.Email);if (existingUser != null){throw new InvalidOperationException("Email already exists.");}// 如果不存在,插入新用户await _context.Users.AddAsync(user);await _context.SaveChangesAsync();}
}
4. 使用异步操作优化性能
异步操作有助于避免线程阻塞,从而提高API的并发处理能力。确保在数据库操作中使用异步方法。
using Microsoft.EntityFrameworkCore;
using Sample1215.Models;namespace Sample1215.Repositories
{public class UserRepository : IUserRepository{private readonly ApplicationDbContext _context;public UserRepository(ApplicationDbContext context){_context = context;}public async Task AddUserAsync(User user){// 使用事务确保操作的原子性using (var transaction = await _context.Database.BeginTransactionAsync()){try{// 检查Email是否已存在var existingUser = await _context.Users.FirstOrDefaultAsync(u => u.Email == user.Email);if (existingUser != null){throw new InvalidOperationException("Email already exists.");}await _context.Users.AddAsync(user);await _context.SaveChangesAsync();await transaction.CommitAsync();}catch (Exception){await transaction.RollbackAsync();throw;}}}}
}
总结
当多个并发线程访问数据库时,可能会遇到数据库连接池耗尽、数据一致性问题以及事务冲突等问题。通过以下策略,可以有效解决这些问题:
- 使用数据库事务:确保每个插入操作都能原子执行,避免数据不一致。
- 限制并发请求:通过信号量或线程池限制并发线程数,防止连接池耗尽。
- 乐观锁:通过检查唯一性约束来避免并发写入冲突。
- 异步操作:使用异步操作提高并发性能,减少阻塞。
这些方法不仅可以提高数据库写入的稳定性,还能提升系统的整体性能和响应能力。
相关文章:
解决几个常见的ASP.NET Core Web API 中多线程并发写入数据库失败的问题
前言 在ASP.NET Core Web API应用程序中,当多个并发线程同时调用新增用户数据的接口时,可能会遇到数据库写入失败的问题。这个问题通常源于多个线程同时访问数据库时,可能会导致以下情况: 数据库连接池耗尽:每个线程…...
让知识更具生命力
在当今快速发展的技术世界中,技术文档的重要性不言而喻。它不仅是知识传递的有效载体,也是团队协作的基石,更是提升产品竞争力的重要工具。然而,编写出一份清晰、完整且实用的技术文档,对于许多开发者和团队来说并非易…...
批量DWG文件转dxf(CAD图转dxf)——c#插件实现
此插件可将指定文件夹及子文件夹下的dwg文件批量转为dxf文件。 (使用方法:命令行输入 “netload” 加载插件,然后输入“dwg2dxf”运行,选择文件夹即可。) 生成dxf在此新建的文件夹路径下,包含子文件夹内的…...
《Django 5 By Example》阅读笔记:p561-p613
《Django 5 By Example》学习第 21 天,p561-p613 总结,总计 53 页。 一、技术总结 1.mixins (1)定义(什么是 mixins?) p570,Mixins are a special kind of multiple inheritance for a class. (2)适用场景(为什么使用?) 1)…...
1. 字符串分割
给定一个非空字符串S,其被N个‘-’分隔成N1的子串,给定正整数K,要求除第一个子串外,其余的子串每K个字符组成新的子串,并用‘-’分隔。对于新组成的每一个子串,如果它含有的小写字母比大写字母多࿰…...
[SAP ABAP] 将内表数据转换为HTML格式
从sflight数据库表中检索航班信息,并将这些信息转换成HTML格式,然后下载或显示在前端 开发步骤 ① 自定义一个数据类型 ty_sflight 来存储航班信息 ② 声明内表和工作区变量,用于存储表头、字段、HTML内容和航班详细信息以及创建字段目录lt…...
计算机网络-应用层
应用层是咱们日常开发中,最常用到的一层 主要涉及到两种情况: 1.使用大佬们已经创建好的应用层协议(后面再讨论,应用层知名的协议有很多,其中的佼佼者就是 HTTP (后面会出单独的文章来讲解))2.自己定义应用…...
SpringEvent 解决 WebUploader 大文件上传解耦问题
一、SpringEvent涉及的相关组件 为了让不熟悉SpringEvent的朋友对Event也有一个大致的印象。这里还是对SpringEvent对象包含的方法和相关组件的应用进行简单的介绍。 1、 事件(Event) 事件是应用程序中发生的某种事情,可以是用户行为、系统…...
KALI安装操作及过程
以下是在计算机上安装 Kali Linux 的详细教程:(通常我直接使用虚拟机) 解压虚拟机安装包,直接在虚拟机中打开KALI (将内存改为4GB) 初始密码账号:kali 一、准备工作 下载 Kali Linux 镜像文件…...
Scala—“==“和“equals“用法(附与Java对比)
Scala 字符串比较—""和"equals"用法 Scala 的 在 Scala 中, 是一个方法调用,实际上等价于调用 equals 方法。不仅适用于字符串,还可以用于任何类型,并且自动处理 null。 Demo: Java 的 在 J…...
[Flutter] : Clipboard
import package:flutter/material.dart; import package:flutter/services.dart; setData Clipboard.setData(ClipboardData(text: "传入的文字内容")); getData Clipboard.getData(Clipboard.kTextPlain) 记录 | Flutter剪切板-刨根问底做一个可以在后台…...
vue2:v-for实现的el-radio-group选中时显示角标,并自定义选中按钮的字体颜色和背景色
项目中需要实现一组预定义查询,每一个查询按钮在选中时右上角显示一个角标,展示当前查询返回的数据条目。 1、text-color="#3785FF" fill="#E6EAF1" 处理选中时的字体颜色和背景色,如上图,分别为蓝色和浅灰色。 2、badge中:value="selectedRadio…...
Dynamics 365 CRM- 后端
Dynamics 365 CRM 后端插件语法示例 public IPluginExecutionContext context null;//上下文 public IOrganizationServiceFactory serviceFactory null;//组织服务工厂对象 public IOrganizationService service null;//Org服务对象//创建执行上下文 context (IPluginExe…...
电脑显示器选购指南2024
选择显示器是五花八门的显示参数,如何选择,以下给出参数说明,及部分参考: 1. 尺寸和分辨率 尺寸(英寸) 根据使用距离和用途选择合适的屏幕尺寸: 21-24 英寸:适合小桌面空间、日常…...
机器学习-多元线性回归
文章目录 代码什么是回归任务什么是多元什么是回归什么是多元线性回归表达式何时使用多元线性回归注意损失函数 代码 https://github.com/FULLK/AI_Study/tree/main/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E5%A4%9A%E5%85%83%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92 什么是回归…...
WEB语义化的新探索:浅析LLMs.txt
【引】有人迷恋使用大模型生成各种有趣的内容, 有人沉醉于大模型相关技术的探索,没有对错,只在于你的乐趣所在。 一项名为 llms.txt 的新提案标志了一些非同寻常的东西的出现: 一个Web网站不仅为人类读者服务,而且为人工智能提供服…...
【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说
关注作者 制造供应链的牛鞭问题与复杂问题主要是从两个方面解决,一是同步化供应链消减从需求到供应的放大效应,二是供应链细分,针对不同的客户、不同的需求供应的匹配策略来应对复杂性,更好的满足客户并以最低的总成本来实现。 对…...
RabbitMQ中的Publish-Subscribe模式
在现代分布式系统中,消息队列(Message Queue)是实现异步通信和解耦系统的关键组件。RabbitMQ 是一个功能强大且广泛使用的开源消息代理,支持多种消息传递模式。其中,Publish/Subscribe(发布/订阅࿰…...
简单了解一下 Go 语言的构建约束?
构建约束是一种在 Go 语言中控制源文件编译条件的方法,它可以让您指定某些文件只在特定的操作系统、架构、编译器或 Go 版本下编译,而在其他环境中自动忽略。这样可以方便您针对不同的平台或场景编写不同的代码,实现条件编译的功能。 构建…...
图像融合算法笔记2024 CDTNet
目录 ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization 依赖项: trilinear 效果图: 推理代码ok 只支持linux系统: ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization 开源地址: GitHub - bcmi/CDTNet-High-Reso…...
我们来对接蓝凌OA --报文格式
题记 数智化办公专家、国家高新技术企业、知识管理国家标准制定者、信创供应商10强…等等,这些和咱们有关系吗!!不好意思,走错片场了,刚和项目经理在甲方那边吹牛B想想刚刚的大饼,看看支付宝余额ÿ…...
npm、yarn、pnpm三者的异同
这个表格将会说明一切: 特性npmyarnpnpm依赖管理方式扁平化管理,嵌套依赖树,可能重复安装扁平化管理喝符号链接,同版本只能安装一次基于硬链接喝符号链接的内容寻址存储安装速度最慢中等(并行安装)最快(得益于硬链接的复用)磁盘空…...
纯CSS实现文本或表格特效(连续滚动与首尾相连)
纯CSS实现文本连续向左滚动首尾相连 1.效果图: 2.实现代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, init…...
信号处理:概念、技术、领域
目录 基本概念 主要技术 应用领域 信号处理是一个涉及分析、修改和再生信号的多学科领域。信号可以是各种形式的,例如声音、图像、视频或其他类型的监测数据。信号处理的主要目标是提取有用的信息并增强信号的质量。以下是信号处理的一些基本概念和应用ÿ…...
Android 中 Activity 和 Fragment 的结合使用经典案例
学习笔记 0. 分析 Activity 与 Fragment 的区别,部分使用的差异 上一篇中我们分析了Activity 与 Fragment 的区别,部分使用的差异。 点我跳转上一篇 1. 单个 Activity 中使用多个 Fragment 这是最常见的用法之一,特别是在单屏幕应用中。通…...
Http协议在网站中的体现
文章目录 1. Http协议简介2. 网站中的体现2.1 访问网站2.2 请求2.3 请求头2.4 请求方式2.5 响应 3. 总结 1. Http协议简介 HTTP(超文本传输协议) 是一种广泛应用于互联网上的应用层协议,用于在Web浏览器和Web服务器之间传输数据。HTTP协议定…...
CTF-WEB: php-Session 文件利用 [第一届国城杯 n0ob_un4er 赛后学习笔记]
step 1 搭建容器 教程 A5rZ 题目 github.com Dockerfile 有点问题,手动修复一下 FROM php:7.2-apacheCOPY ./flag /root COPY ./readflag / COPY ./html/ /var/www/html/ COPY ./php.ini /usr/local/etc/php/php.ini COPY ./readflag /readsecretRUN chmod 755 /var/www…...
《计算机视觉:瓶颈之辩与未来之路》
一、计算机视觉的崛起 计算机视觉是使用计算机模仿人类视觉系统的科学,让计算机拥有类似人类提取、处理、理解和分析图像以及图像序列的能力。它是一个多学科交叉的领域,与机器视觉、图像处理、人工智能、机器学习等领域密切相关。 计算机视觉行业可分为…...
黑皮书-计算机科学导论02
目录 第二部分:计算机硬件 第5章计算机组成 5.1中央处理单元 Ⅰ.算数逻辑单元 Ⅱ.控制单元 Ⅲ.寄存器 5.2主存储器 Ⅰ.随机存取存储器(RAM) Ⅱ.只读存储器(ROM) 高速缓冲存储器(Cache) 5.3输入/输出子系统 Ⅰ.非存储设备 Ⅱ.存储设备(辅助存…...
React--》如何高效管理前端环境变量:开发与生产环境配置详解
在前端开发中,如何让项目在不同环境下表现得更为灵活与高效,是每个开发者必须面对的挑战,从开发阶段的调试到生产环境的优化,环境变量配置无疑是其中的关键。 env配置文件:通常用于管理项目的环境变量,环境…...
初始Python篇(6)—— 字符串
找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: Python 目录 字符串的常见操作 格式化字符串 占位符 f-string 字符串的 format 方法 字符串的编码与解码 与数据验证相关的方法 …...
【数字花园】个人知识库网站搭建:⑤本地构建+云服务器部署数字花园plus
目录 写在前面:数字花园的定义[[数字花园]]网站的构建原理包括三个步骤:[[我的数字花园搭建笔记]] 现在的部署流程一、本地操作详细教程-2.前置步骤(前面的文章都提过)-1.创建github中转库0. 本地环境配置基础环境:git…...
力扣题目 - 3264.K 次乘运算后的最终数组I
题目 还需要你前往力扣官网查看详细的题目要求 地址 1.给你一个整数数组 nums ,一个整数 k 和一个整数 multiplier 。2.你需要对 nums 执行 k 次操作,每次操作中:找到 nums 中的 最小 值 x ,如果存在多个最小值,选择最…...
Java常用 Date 时间格式化、Calender日历、正则表达式的用法
目录 1. SimpleDateFormat 日期格式化类 1.1 Date 类型转 String 1.2 String 类型转 Date 2. Calendar 日历类 3. 正则表达式 3.1 正则表达式的组成部分 3.2 手机号正则表达式 3.3 常用密码校验正则表达式 1. SimpleDateFormat 日期格式化类 SimpleDateFormat 是Java中…...
网页爬虫技术全解析:从基础到实战
引言 在当今信息爆炸的时代,互联网上的数据量每天都在以惊人的速度增长。网页爬虫(Web Scraping),作为数据采集的重要手段之一,已经成为数据科学家、研究人员和开发者不可或缺的工具。本文将全面解析网页爬虫技术&…...
细说STM32F407单片机SPI基础知识
目录 一、 SPI接口和通信协议 1、 SPI硬件接口 (1)MOSI(Master Output Slave Input) (2)MISO(Master Input Slave Output) (3)SCK 2、SPI传输协议 (1)CPHA0时的数据传输时序 …...
【OJ题解】面试题三步问题
个人主页: 起名字真南的CSDN博客 个人专栏: 【数据结构初阶】 📘 基础数据结构【C语言】 💻 C语言编程技巧【C】 🚀 进阶C【OJ题解】 📝 题解精讲 目录 **题目链接****解题思路****1. 问题分析****2. 递归思路****3. 优化方案&a…...
Linux vi/vim 编辑器使用教程
Linux vi/vim 编辑器使用教程 引言 Linux 系统中的 vi 和 vim 是非常强大的文本编辑器,它们以其高效性和灵活性而闻名。vim 是 vi 的增强版,提供了更多的功能和改进的用户界面。本文将详细介绍 vi/vim 的基本用法,包括打开文件、编辑文本、…...
长安大学《2024年812自动控制原理真题》 (完整版)
本文内容,全部选自自动化考研联盟的:《长安大学812自控考研资料》的真题篇。后续会持续更新更多学校,更多年份的真题,记得关注哦~ 目录 2024年真题 Part1:2024年完整版真题 2024年真题...
服务器一般装什么系统?
在服务器管理中,操作系统的选择是一个关键因素,它直接影响到服务器的稳定性、性能和可维护性。那么为什么有些服务器选择Linux,而不是Windows?选择合适的操作系统对服务器的性能和安全性有多么重要? 在众多操作系统中…...
Gitlab ci/cd 从0-1持续集成持续发布前端
关于gitlab ci/cd,就是实现DevOps的能力,即Development &Operations的缩写,也就是开发&运维。CI/CD 指的是软件开发的持续集成方法,我们可以持续构建、测试和部署软件。通过持续方法的迭代能使得我们减少在错误代码或者错…...
#GC4049. GC.2017---. GC.2016.六年级
这套题包含了历年真题,包含了前面我写的博客中的题目,十分重要!!!!要考试的同学可以参考一下!! 此套题限时3小时。 #GC4049. GC.2017.六年级.01.更多闰年 题目描述 在 smoj 网站上…...
UE5中实现Billboard公告板渲染
公告板(Billboard)通常指永远面向摄像机的面片,游戏中许多技术都基于公告板,例如提示拾取图标、敌人血槽信息等,本文将使用UE5和材质节点制作一个公告板。 Gif效果: 网格效果: 1.思路 通过…...
Android系统(android app和系统架构)
文章目录 AndroidAndroid Apps四大组件 Android系统Platform API之下:一个微笑内核adb(Android Debug Bridge) Android包管理机制Android的Intent机制参考 Android LinuxFrameworkJVM 在Linux/Java上做了个二次开发?并不完全是:Android定义…...
docker设置容器自动启动
说起开机自动启动应该很多人都遇到过,我们公司做的系统很多的中间件都没有设置开机自动启动然后中间修改问题又设置了一些临时生效的文件,开始的时候大家都不以为意,知道公司陆续有人离职入职管理交接一塌糊涂,项目成了历史遗留问…...
在 React 中,创建和嵌套组件、添加标签和样式、显示数据、渲染条件和列表、对事件做出响应并更新界面以及在组件间共享数据是常见的任务
文章目录 1. 创建和嵌套组件创建组件嵌套组件 2. 添加标签和样式添加标签添加样式 3. 显示数据显示静态数据显示动态数据 4. 渲染条件和列表条件渲染列表渲染 5. 对事件做出响应并更新界面处理事件 6. 在组件间共享数据使用 Context API react 如何创建和嵌套组件 如何添加标签…...
Android命令行工具--dumpsys
dumpsys 是一种在 Android 设备上运行的工具,可提供有关系统服务的信息。可以使用 Android 调试桥 (adb) 从命令行调用 dumpsys,获取在连接的设备上运行的所有系统服务的诊断输出。 此输出通常比您想要的更详细,因此请使用此页面上的命令行选…...
设计模式-访问者模式
背景 做一个对歌手的评价系统,观众分为男人和女人,分别对歌手做出自己的评价。 传统思路: 做一个person父类,Man 和 Woman分别继承自这个父类,在这两个类中执行各自操作。 问题: 可拓展性差࿰…...
Vue集成阿里云点播实现视频上传
实现方式有多种,如下是我的实现方式: 一、下载点播插件,在 public 下的 index.html 中引入阿里云点播需要的 js 插件,js 文件最好放在 cdn 上,,这里以放在 public 文件夹下的 static 文件夹中为例: <s…...
ByteByteGo-Forward/Reverse Proxy正/反向代理
原文链接 EP137: Proxy Vs Reverse proxy - ByteByteGo Newsletter 参考链接 Forward proxy vs. reverse proxy: Whats the difference? | TheServerSide 正向代理 (Forward Proxy) 位置:用户设备 和 互联网 之间 用途:保护客…...