从CRUD到高级功能:EF Core在.NET Core中全面应用(三)
目录
IQueryable使用
原生SQL使用
实体状态跟踪
全局查询筛选器
并发控制使用
IQueryable使用
在EFCore中IQueryable是一个接口用于表示可查询的集合,它继承自IEnumerable但具有一些关键的区别,使得它在处理数据库查询时非常有用,普通集合的版本(IEnumerable)是在内存中过滤(客户端评估),而IQueryable版本则是把查询操作翻译成SQL语句(服务器端评估):
接下来我们开始讲解其简单的应用,如下所示是两种使用的代码,基本上都一样,唯一区别在于两种在执行查询时的行为有所不同,如下所示:
IQueryable:查询会被延迟执行并且它能将LINQ查询转换为SQL以便在数据库中执行,适合处理大规模数据。
IEnumerable:查询会立即执行适合用于内存中的数据集合但无法进行数据库优化,因此性能较差。
class Program
{static void Main(string[] args){using (MyDbContext ctx = new MyDbContext()){IEnumerable<Class> classes1 = ctx.Classes.Include(t => t.Students);IQueryable<Class> classes2 = ctx.Classes.Include(t => t.Students);foreach (var c in classes1){Console.WriteLine($"Class Name: {c.Name}");foreach (var s in c.Students){Console.WriteLine($"\tStudent Name: {s.Name}, Age: {s.Age}");}}foreach (var c in classes2){Console.WriteLine($"Class Name: {c.Name}");foreach (var s in c.Students){Console.WriteLine($"\tStudent Name: {s.Name}, Age: {s.Age}");}}}}
}
两者的区别如下所示:
特性 | IQueryable | IEnumerable |
---|---|---|
执行时机 | 延迟执行,查询会转化为 SQL 并在数据库中执行 | 即时执行,查询在内存中执行 |
数据来源 | 通常用于数据库查询,支持远程数据源 | 通常用于内存中的集合 |
性能优化 | 利用数据库的索引和优化进行查询 | 数据已经在内存中,无法优化 |
常见用途 | 用于数据库查询(如 Entity Framework) | 用于内存中的集合,如 List、Array 等 |
延迟执行:IQueryable支持延迟加载,执行查询的集合时只有在查询被执行时才会真正访问数据库或数据源,查询会在执行时转化为相应的SQL语句或者其他数据源的查询语言,只有在需要数据时查询才会被执行,如下所示:
// 假设 context 是一个 DbContext 对象
IQueryable<User> query = context.Users.Where(u => u.Age > 18);
// 这个查询还没有执行,只有调用 ToList() 或其他方法时,查询才会发送到数据库执行
var result = query.ToList(); // 执行查询,返回结果
IQueryable只是代表一个“可以放到数据库服务器去执行的查询”,它没有立刻执行只是可以被执行而已,对于IQueryable接口调用非终结方法的时候不会执行查询,而调用终结方法的时候则会立刻执行查询。
一个方法的返回值类型如果是IQueryable类型,那么这个方法一般就是非终结方法,否则就是终结方法:
// 终结方法:
ToArrar()、ToList()、Min()、Max()、Count()等// 非终结方法:
GroupBy()、OrderBy()、Include()、Skip()、Take()等
IQueryable代表一个对数据库中数据进行查询的一个逻辑,这个查询是一个延迟查询,我们可以调用非终结方法向IQueryable中添加查询逻辑,当执行终结方法的时候才真正生成SQL语句来执行查询,可以实现以前要靠SQL拼接实现的动态查询逻辑。
分页查询:IQueryable是用于支持延迟执行的LINQ查询的一种接口,在分页查询的实现中我们通常结合Skip()和Take()方法来控制结果集的起始位置和返回的数量,分页查询通过限制数据的加载量来提高查询效率,尤其在处理大数据集时,如下所示:
// Skip() 方法: 用于跳过前N条记录,通常用来跳过前几页的数据。
// Take() 方法: 用于返回指定数量的记录。
public IQueryable<T> GetPagedResults<T>(IQueryable<T> query, int pageNumber, int pageSize)
{return query.Skip((pageNumber - 1) * pageSize) // 跳过前几页的记录.Take(pageSize); // 获取当前页的记录
}
这里我们通过分页去查询我们数据库当中的学生表,以每页2条数据为准,如下所示:
获取数据: 从数据库获取数据主要分为以下两种:
1)DataReader:分批从数据库服务器读取数据,内存占用小、DB连接占用时间长。
2)DataTable:把所有数据都一次性从数据库服务器都加载到客户端内存中,内存占用大节省DB连接。
我们可以通过insert into select多插入一些数据,然后加上Delay/Sleep的遍历IQueryable,在遍历执行的过程中停止MySQL服务器,可以验证IQueryable内部就是在调用DataReader,其优点是节省客户端内存,缺点是如果处理的慢就会长时间占用连接。
如果想IQueryable一次性加载数据到内存中,可以用IQueryable的ToArrary()、ToArrayAsync()、ToList()、ToListAsync()等方法,等ToArray()执行完毕再断服务器试一下。
原生SQL使用
尽管EF Core已经非常强大,但是仍然存在着无法被写成标准EF Core调用方法的SQL语句,少数情况下仍然需要写原生的SQL,这里有三种情况:非查询语句、实体查询、任意SQL查询,如下:
非查询语句:这里我们可以通过ExecuteSqlInterpolatedAsync进行字符串插值拼接,其会自动处理SQL参数,如下所示:
namespace Program
{class Program{static async Task Main(string[] args){string description = "test";using (MyDbContext ctx = new MyDbContext()){await ctx.Database.ExecuteSqlInterpolatedAsync($"INSERT INTO T_Class (Name, Description) SELECT Name, {description} FROM T_Students WHERE Id > 2");}}}
}
得到的结果如下所示:
字符串内插如果赋值给string变量,就是字符串拼接,字符串内插如果赋值FormattableString变量,编译器就会构造FormattableString对象,该对象会进行参数化SQL处理,一定程度上防止了SQL注入攻击,如下所示:
实体查询:如果要执行的原生SQL是一个查询语句并且查询的结果也能对应一个实体,就可以调用对应实体的DbSet的FromSqlInterpolated()方法来执行一个查询的SQL语句,同样使用字符串内插来传递参数,如下所示:
namespace Program
{class Program{static async Task Main(string[] args){string description = "%test%";using (MyDbContext ctx = new MyDbContext()){var queryable = ctx.Classes.FromSqlInterpolated(@$"select * from T_Class where Description like {description}");foreach (var item in queryable){Console.WriteLine(item.Id+" "+item.Name+" "+item.Description);}}}}
}
查询的结果如下所示:
FromSqlInterpolated()方法的返回值是IQueryable类型的,因此我们可以在执行IQueryable之前对IQueryable进行进一步的处理,把只能用原生SQL语句写的逻辑用FromSqlInterpolated()去执行,然后把分页、分组、二次过滤、排序、Include等其他逻辑尽可能仍然使用EF Core的标准去操作实现。
局限性:SQL查询必须返回实体类型对应数据库表的所有列,结果集中的列必须与属性映射到的列名称匹配,只能单表查询而不能使用join语句进行关联查询,但是可在查询后面使用Include来进行关联数据的获取。
任意SQL查询:这里使用DbConnection来获取数据库的连接对象,而不借用EF Core生成的SQL进行查询,如下所示:
namespace Program
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){DbConnection conn = ctx.Database.GetDbConnection(); // 获取数据库连接if (conn.State != System.Data.ConnectionState.Open){await conn.OpenAsync(); // 打开数据库连接}using (DbCommand cmd = conn.CreateCommand()){cmd.CommandText = "select * from T_Class where Description like '%test%'";using (DbDataReader reader = await cmd.ExecuteReaderAsync()){while (await reader.ReadAsync()){Console.WriteLine(reader["Id"] + " " + reader["Name"] + " " + reader["Description"]);}}}}}}
}
最终得到的结果如下所示:
总结:一般Ling操作就够了尽量不用写原生SQL,非查询SQL用ExecuteSqllnterpolated(),针对实体的SQL查询用FromSqllnterpolated(),复杂SQL查询用ado.net的方式或者Dapper等
实体状态跟踪
实体状态跟踪:是指框架如何追踪实体对象在其生命周期中的状态变化,这些状态帮助EFCore确定如何与数据库进行交互,以便在保存更改时正确生成SQL查询。
EFCore使用一个叫做Change Tracker的机制来跟踪实体的状态,确保数据库中的数据与应用程序中的实体对象保持一致,其实体对象主要有以下五种状态:
已添加(Added):实体是新创建的尚未保存到数据库中,EFCore将会把这些实体作为新的记录插入到数据库中,如下:
var newStudent = new Student { Name = "John" }; dbContext.Students.Add(newStudent); // 设置状态为 Added
未改变(Unchanged):实体的状态没有发生变化,EFCore不会对其生成任何SQL语句,实体的属性值与数据库中的数据一致,如下:
var student = dbContext.Students.Find(1); // 假设没有更改属性 // 没有显式的修改,实体状态保持 Unchanged
已修改(Modified):实体已存在并且它的属性值发生了变化,EFCore会在保存更改时生成一个 update sql语句将这些更改同步到数据库中,如下:
var student = dbContext.Students.Find(1); student.Name = "Jane"; // 设置状态为 Modified dbContext.Students.Update(student);
已删除(Deleted):实体被标记为删除并且当保存更改时,EFCore会生成deleted sql语句,需要显式调用删除操作来设置实体为删除状态,如下:
var student = dbContext.Students.Find(1); dbContext.Students.Remove(student); // 设置状态为 Deleted
已分离(Detached):实体不再被EFCore上下文跟踪,通常是因为实体从上下文中移除或在数据库之外创建,如果试图对这些实体做更改EFCore不会追踪它们,因此不会执行任何操作,如下:
var student = dbContext.Students.Find(1); dbContext.Entry(student).State = EntityState.Detached; // 设置状态为 Detached
如果想查看实体状态,这里我们可以使用DbContext的Entry()方法来获得实体在EF Core中的跟踪信息对象EntityEntry,EntityEntry类的State属性代表实体的状态,通过DebugView.LongView属性可以看到实体的变化信息,如下所示:
var student = dbContext.Students.Find(1);
var entry = dbContext.Entry(student);
Console.WriteLine(entry.State); // 输出实体的当前状态(例如 Added, Modified, Unchanged, 等)
DbContext会根据跟踪的实体的状态,在SaveChanges()的时候,根据实体状态的不同生成update、delete、insert等sql语句来把内存中实体的变化更新到数据库中。
默认情况下EFCore会追踪所有实体的状态,如果不想追踪某些实体的状态可以使用AsNoTracking方法禁用状态跟踪,这通常用于查询操作以提高性能:
var students = dbContext.Students.AsNoTracking().ToList();
如果我们确认我们的操作只会查询不会被修改、删除等,那么这里我们就可以使用AsNoTracking()方法来提升性能,降低内存占用,如下所示:
全局查询筛选器
EFCore中的全局查询筛选器是一种用于在整个应用程序中自动应用的查询条件,它允许在查询时自动对数据进行过滤,确保数据的一致性和安全性而无需在每个查询中显式添加筛选条件,常用的场景如下所示:
软删除:通过全局查询筛选器确保删除的记录在查询中不被返回,而无需显式地为每个查询添加where子句。
假设我们有一个Product实体,其中包含一个IsDeleted属性用来标记某个产品是否被删除,我们可以在OnModelCreating方法中为Product实体配置全局查询筛选器确保查询时自动排除已删除的产品,如下所示:
public class ApplicationDbContext : DbContext
{public DbSet<Product> Products { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){// 为 Product 实体添加全局查询筛选器modelBuilder.Entity<Product>().HasQueryFilter(p => !p.IsDeleted);}
}
如果想查询已经删除的数据,并且我们也已经配置了全局忽略删掉数据的过滤器,这里我们可以在要查询删除数据的地方添加上忽略全局过滤器的函数,如下所示:
多租户:为每个租户添加自动的筛选条件,确保每个租户只访问自己的数据。
这里可以使用多个条件创建复杂的筛选器,例如如果有一个TenantId字段来支持多租户功能,可以根据租户ID创建全局筛选器,这种方式确保了在每次查询Product实体时都会自动根据当前租户的ID过滤数据,如下所示:
modelBuilder.Entity<Product>().HasQueryFilter(p => p.TenantId == currentTenantId);
并发控制使用
并发控制用于确保多个用户或多个进程对数据库进行并发访问时,不会产生数据冲突或不一致的问题,避免多个用户同时操作资源造成的并发冲突问题,例如:统计点击量。最好的解决方案就是:非数据库解决方案。如果从数据库层面来处理的话,EFCore支持如下两种主要的并发控制机制:
悲观并发控制:假设并发冲突的可能性较大,因此会通过锁定数据来防止其他用户修改正在处理的数据。在悲观并发控制中EFCore支持使用数据库的锁机制(如行级锁)来实现并发控制。
悲观并发控制一般采用行锁、表锁等排他锁对资源进行锁定,确保同时只有一个使用者操作被锁定的资源,EF Core没有封装悲观并发控制的使用,需要开发人员编写原生SQL语句来使用悲观并发控制,不同数据库的语法不一样。
这里我们通过一个占据房子书写房名的案例进行讲解,这里通过MySQL方案来实现,如下:
class House {public long Id {get; set;}public string Name {get; set;}public string Owner {get; set;}
}
// MySQL方案
select * from T_Houses Where Id = 1 for update
如果有其他的查询操作也使用for update来查询id=1的这条数据的话,那么查询就会被挂起直到针对这条数据的更新操作完成从而释放这个行锁,代码才会继续执行,如下所示:
namespace Program
{class Program{static async Task Main(string[] args){Console.WriteLine("请输出您的名字");string name = Console.ReadLine();using (MyDbContext ctx = new MyDbContext()){var houses = ctx.Houses.Single(h => h.Id == 1);if (!string.IsNullOrEmpty(houses.Owner)){if (houses.Owner == name){Console.WriteLine("恭喜你,你已经买过了");} else{Console.WriteLine($"房子已经被{houses.Owner}买走了");}return;}houses.Owner = name;Thread.Sleep(10000);Console.WriteLine("恭喜你,你已经买到了房子");ctx.SaveChanges();Console.ReadKey();}}}
}
上面代码,如果我们不进行并发控制的话,下面如果我们同时执行两个人抢房子,两者都会出现买到了房子,但是实际上房子最后还是被Hack买到了,如下
接下来我们在程序中添加事务操作,如下所示:
namespace Program
{class Program{static async Task Main(string[] args){Console.WriteLine("请输出您的名字");string name = Console.ReadLine();using (MyDbContext ctx = new MyDbContext())using (var tx = ctx.Database.BeginTransaction()) // 开启事务{Console.WriteLine(DateTime.Now+"正在为您查询房源信息");var houses = ctx.Houses.FromSqlInterpolated($"select * from T_House where Id = 1 for update").Single();Console.WriteLine(DateTime.Now+"房源信息完毕");if (!string.IsNullOrEmpty(houses.Owner)){if (houses.Owner == name){Console.WriteLine("恭喜你,你已经买过了");} else{Console.WriteLine($"房子已经被{houses.Owner}买走了");}Console.ReadKey();return;}houses.Owner = name;Thread.Sleep(10000);Console.WriteLine("恭喜你,你已经买到了房子");ctx.SaveChanges();Console.WriteLine("正在为您保存房源信息");tx.Commit(); // 提交事务Console.ReadKey();}}}
}
得到的结果如下所示,可以看到我们的并发操作以及处理好了:
总结: 悲观并发控制的使用比较简单,锁是独占排他的,如果系统并发量很大的话会严重影响性能,如果使用不当的话甚至会导致死锁,这点尤为重要,所以要根据实际情况进行选择使用。
乐观并发控制:假设并发冲突较少,因此允许多个操作同时对数据进行修改,在提交更改时EFCore会检查数据是否被其他操作修改过,如果数据已被修改当前操作会被拒绝并抛出 DbUpdateConcurrencyException异常。
举例:当update的时候如果数据库中的Owner值已经被其他操作者更新为其他值了,那么where语句的值就会被设为false,因此这个update语句影响的行数就是0,EFCore就知道发生并发冲突了,因此SaveChanges()方法就会抛出DbUpdateConcurrencyException异常,如下所示:
1)标记并发字段:在实体类或配置类中标记一个字段作为并发标记,通常是一个时间戳字段或者是一个列,EFCore使用该字段来检测数据是否在并发操作期间被修改过,如下所示:
namespace test
{internal class HouseConfig : IEntityTypeConfiguration<House>{public void Configure(EntityTypeBuilder<House> builder){builder.ToTable("T_House");builder.Property(x => x.Name).IsRequired();builder.Property(x => x.Owner).IsConcurrencyToken(); // 并发标记}}
}
2)处理并发冲突:当发生并发冲突时,EFCore会抛出DbUpdateConcurrencyException异常,可以捕获此异常并根据需求进行处理,比如:
namespace Program
{class Program{static async Task Main(string[] args){Console.WriteLine("请输出您的名字");string name = Console.ReadLine();using (MyDbContext ctx = new MyDbContext()){Console.WriteLine(DateTime.Now + "正在为您查询房源信息");var houses = ctx.Houses.Single(h => h.Id == 1);Console.WriteLine(DateTime.Now + "房源信息完毕");if (!string.IsNullOrEmpty(houses.Owner)){if (houses.Owner == name){Console.WriteLine("恭喜你,你已经买过了");}else{Console.WriteLine($"房子已经被{houses.Owner}买走了");}Console.ReadKey();return;}houses.Owner = name;Console.WriteLine("恭喜你,你已经买到了房子");try{ctx.SaveChanges();}catch (DbUpdateConcurrencyException ex){Console.WriteLine("并发访问冲突");var entry = ex.Entries.Single();string newValue = entry.GetDatabaseValues().GetValue<string>("Owner");Console.WriteLine($"房子已经被{newValue}买走了");}Console.ReadKey();}}}
}
最终呈现的效果如下所示:
相关文章:

从CRUD到高级功能:EF Core在.NET Core中全面应用(三)
目录 IQueryable使用 原生SQL使用 实体状态跟踪 全局查询筛选器 并发控制使用 IQueryable使用 在EFCore中IQueryable是一个接口用于表示可查询的集合,它继承自IEnumerable但具有一些关键的区别,使得它在处理数据库查询时非常有用,普通集…...

【记录】Jenkins版本及JDK关系介绍的官网地址
Redhat Jenkins Packages...

vue3-json-viewer和vue-json-pretty插件使用,vue3 json数据美化展示
本文介绍vue3如何进行json数据pretty展示 1 vue3-json-viewer 1.1 安装 npm install vue3-json-viewer --save1.2 全局引入 在main.ts中引入,然后直接在组件中使用 import { createApp } from vue import App from ./App.vue import JsonViewer from "vue3…...

python转转商超书籍信息爬虫
1基本理论 1.1概念体系 网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,可以按照我们设置的规则自动化爬取网络上的信息,这些规则被称为爬虫算法。是一种自动化程序,用于从互联网上抓取数据。爬虫通过模拟浏览器的行为,访问网页并…...

Spring Boot 中的 InitializingBean:Bean 初始化背后的故事
在 Spring Boot 应用中,Bean 的生命周期管理至关重要。InitializingBean 接口允许 Bean 在完成属性注入后执行自定义初始化逻辑。本文将深入探讨 InitializingBean 接口在 Spring Boot 中的应用,揭示其工作原理,并分享一些最佳实践࿰…...

微信小程序:实现单选,多选,通过变量控制单选/多选
一、实现单选功能 微信小程序提供了 radio 组件来实现单选功能。radio 组件需要配合 radio-group 使用。 1. WXML 代码 <radio-group bindchange"onRadioChange"><label wx:for"{{items}}" wx:key"id"><radio value"{{it…...

MOS怎样选型,步骤详解
一:选用N沟道还是P沟道 为设计选择正确器件的第一步是决定采用N沟道还是P沟道MOSFET。在典型的功率应用中,当一个MOSFET接地,而负载连接到干线电压上时,该MOSFET就构成了低压侧开关。在低压侧开关中,应采用N沟道M…...

CMake技术细节:解决未定义,提供参数
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...

1688 满足跨境业务需求而提供的一组 API 接口
1688 跨境属性接口系列是 1688 开放平台为满足跨境业务需求而提供的一组 API 接口,其中最主要的是1688.item_get : 一:1688.item_get接口 接口功能:主要用于查询 1688 商品的跨境属性,为开发者和商家提供了获取商品跨境关键信息…...

物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境:飞腾派开发板(国产E2000处理器) 软件环境:飞腾派OS(Phytium Pi OS) 硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板…...

计算机网络 (51)鉴别
前言 计算机网络鉴别是信息安全领域中的一项关键技术,主要用于验证用户或信息的真实性,以及确保信息的完整性和来源的可靠性。 一、目的与重要性 鉴别的目的是验明用户或信息的正身,对实体声称的身份进行唯一识别,以便验证其访问请…...

【Docker】搭建一个功能强大的自托管虚拟浏览器 - n.eko
前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建,DSM版本为 DSM 7.2.2-72806 Update 2。 n.eko 支持多种类型浏览器在其虚拟环境中运行,本次教程使用 Chromium 浏览器镜像进行演示,支持访问内网设备和公网地址。 简介 n.eko 是…...

论文笔记(六十二)Diffusion Reward Learning Rewards via Conditional Video Diffusion
Diffusion Reward Learning Rewards via Conditional Video Diffusion 文章概括摘要1 引言2 相关工作3 前言4 方法4.1 基于扩散模型的专家视频建模4.2 条件熵作为奖励4.3 训练细节 5 实验5.1 实验设置5.2 主要结果5.3 零样本奖励泛化5.4 真实机器人评估5.5 消融研究 6 结论 文章…...

探索 Stable-Diffusion-Webui-Forge:更快的AI图像生成体验
目录 简介🌟 主要特点📥 安装步骤1. 下载2. 配置环境和安装依赖3. 模型目录说明 🚀 运行 Stable-Diffusion-Webui-Forge1. 进入项目目录2. 运行项目3. 打开页面 🎨 使用体验常见问题📝 小结 简介 Stable-Diffusion-We…...

Redis使用基础
1 redis介绍 Redis(Remote Dictionary Server ),即远程字典服务 ! 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并…...

PyCharm+RobotFramework框架实现UDS自动化测试- (四)项目实战0x10
1.环境搭建 硬件环境:CANoe、待测设备(包含UDS诊断模块) 2.pythonPyCharm环境 pip install robotframework pip install robotframework-ride pip install openpyxl pip install udsoncan pip install python-can pip install can-isotp3…...

【TCP】rfc文档
tcp协议相关rfc有哪些 TCP(传输控制协议)是一个复杂的协议,其设计和实现涉及多个RFC文档。以下是一些与TCP协议密切相关的RFC文档列表,按照时间顺序排列,涵盖了从基础定义到高级特性和优化的各个方面: 基…...

【SpringCloud】黑马微服务学习笔记
目录 1. 关于微服务 ?1.1 微服务与单体架构的区别 ?1.2 SpringCloud 技术 2. 学习前准备 ?2.1 环境搭建 ?2.2 熟悉项目 3. 正式拆分 ?3.1 拆分商品功能模块 ?3.2 拆分购物车功能模块 4. 服务调用 ?4.1 介绍 ?4.2 RustTemplate?的使用 4.3 服务治理-注册中…...

梯度提升决策树树(GBDT)公式推导
### 逻辑回归的损失函数 逻辑回归模型用于分类问题,其输出是一个概率值。对于二分类问题,逻辑回归模型的输出可以表示为: \[ P(y 1 | x) \frac{1}{1 e^{-F(x)}} \] 其中 \( F(x) \) 是一个线性组合函数,通常表示为ÿ…...

【MySQL】表的基本操作
??表的基本操作 文章目录: 表的基本操作 创建查看表 创建表 查看表结构 表的修改 表的重命名 表的添加与修改 删除表结构 总结 前言: 在数据库中,数据表是存储和组织数据的基本单位,对于数据表的操作是每个程序员需要烂熟…...

项目中使用的是 FastJSON(com.alibaba:fastjson)JSON库
从你的 pom.xml 文件中可以看到,项目明确依赖了以下 JSON 库: FastJSON: <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version> </depende…...

Flutter中PlatformView在鸿蒙中的使用
Flutter中PlatformView在鸿蒙中的使用 概述在Flutter中的处理鸿蒙端创建内嵌的鸿蒙视图创建PlatformView创建PlatformViewFactory创建plugin,注册platformview注册插件 概述 集成平台视图(后称为平台视图)允许将原生视图嵌入到 Flutter 应用…...

音频入门(一):音频基础知识与分类的基本流程
音频信号和图像信号在做分类时的基本流程类似,区别就在于预处理部分存在不同;本文简单介绍了下音频处理的方法,以及利用深度学习模型分类的基本流程。 目录 一、音频信号简介 1. 什么是音频信号 2. 音频信号长什么样 二、音频的深度学习分…...

规避路由冲突
路由冲突是指在网络中存在两个或多个路由器在进行路由选择时出现矛盾,导致网络数据包无法正确传输,影响网络的正常运行。为了规避路由冲突,可以采取以下措施: 一、合理规划IP地址 分配唯一IP:确保每个设备在网络中都有…...

SQLmap 自动注入 -02
1: 如果想获得SQL 数据库的信息,可以加入参数: -dbs sqlmap -u "http://192.168.56.133/mutillidae/index.php?pageuser-info.php&usernamexiaosheng&passwordabc&user-info-php-submit-buttonViewAccountDetails" --batch -p username -dbs…...

4.JoranConfigurator解析logbak.xml
文章目录 一、前言二、源码解析GenericXMLConfiguratorlogback.xml解析通过SaxEvent构建节点model解析model节点DefaultProcessor解析model 三、总结 一、前言 上一篇介绍了logback模块解析logback.mxl文件的入口, 我们可以手动指定logback.xml文件的位置, 也可以使用其它的名…...

React 19 新特性总结
具体详见官网: 中文:React 19 新特性 英文:React 19 新特性 核心新特性 1. Actions 解决问题:简化数据变更和状态更新流程 以前需要手动处理待定状态、错误、乐观更新和顺序请求需要维护多个状态变量(isPending, error 等) 新…...

kafka学习笔记6 ACL权限 —— 筑梦之路
在Kafka中,ACL(Access Control List)是用来控制谁可以访问Kafka资源(如主题、消费者组等)的权限机制。ACL配置基于Kafka的kafka-acls.sh工具,能够管理对资源的读取、写入等操作权限。 ACL介绍 Kafka的ACL是…...

【Java】Java抛异常到用户界面公共封装
前言 在Java中处理代码运行异常是常见的技术点之一,我们大部分会使用封装的技巧将异常进行格式化输出,方便反馈给用户界面,也是为了代码复用 看看这行代码是怎么处理异常的 CommonExceptionType.SimpleException.throwEx("用户信息不…...

基于Redis实现短信验证码登录
目录 1 基于Session实现短信验证码登录 2 配置登录拦截器 3 配置完拦截器还需将自定义拦截器添加到SpringMVC的拦截器列表中 才能生效 4 Session集群共享问题 5 基于Redis实现短信验证码登录 6 Hash 结构与 String 结构类型的比较 7 Redis替代Session需要考虑的问题 8 …...