为什么反射慢? - 北冥有鱼要继续奋斗 - 博客园

mikel阅读(193)

来源: 为什么反射慢? – 北冥有鱼要继续奋斗 – 博客园

反射机制就是通过字节码文件对象获取成员变量、成员方法和构造方法,然后进一步获取它们的具体信息,如名字、修饰符、类型等。

反射机制的性能较低有很多原因,这里详细总结以下4点原因:

(1)JIT优化受限:
JIT 编译器的优化是基于静态分析和预测的。反射是一种在运行时动态解析类型信息的机制,在编译时无法确定反射调用的具体方法,因此编译器无法对这些代码进行静态分析,从而无法进行一些JIT优化,比如:

内联优化受限:JIT 编译器通常会对频繁调用的方法进行内联优化,将方法调用替换为直接的代码。但是,由于反射调用的方法在运行时才能确定,因此 JIT 编译器无法进行有效的内联优化。

无法进行即时编译:因为反射调用的方法在运行时才能确定,因此在解释执行阶段,我们无法确定反射调用的方法会被执行多少次,会不会成为热点代码,也就无法对其进行即时编译优化。

(2)反射中频繁的自动拆装箱操作会导致应用性能下降:
在反射中,当你调用一个方法时,由于在编译时不知道具体要调用的方法参数类型,因此需要用最通用的引用类型来处理所有的参数,即Object。例如,通过Method对象调用方法时,使用的invoke方法签名大致如下:

public Object invoke(Object obj, Object... args)

对于基本数据类型的参数,它们必须被装箱成对应的包装类(如IntegerDouble等),以便它们可以作为对象被传递。在方法实际执行时,如果方法的参数是基本类型,JVM需要基本类型的值,而不是它们的包装类对象。因此,JVM会自动进行拆箱。例如,如果你通过反射调用的方法期望得到一个int类型的参数,但你传入的是Integer,在调用过程中JVM会自动将Integer对象拆箱为int类型。装箱和拆箱操作涉及到额外的对象创建(装箱时)和对象值的提取(拆箱时),在高性能要求的场景下,过度的装箱和拆箱可能会导致性能瓶颈。此外,由于装箱操作导致创建了许多短生命周期的对象,这些对象在成为垃圾后,需要通过垃圾回收过程来回收内存资源,当有大量对象需要回收时,GC会占用更多的CPU资源,可能导致应用性能暂时下降。

(3)遍历操作
反射在调用方法时会从方法数组中遍历查找,这对普通的方法调用来说是不需要的。

(4)方法访问检查
每次使用反射调用方法时,JVM都要检查是否允许访问该方法,例如是否为私有方法等。这些访问检查对普通的方法调用来说是不需要的,因为这些检查都是在编译时完成的。

C# 使用模式匹配的好处,因为好用所以推荐~ - 万雅虎 - 博客园

mikel阅读(158)

来源: C# 使用模式匹配的好处,因为好用所以推荐~ – 万雅虎 – 博客园

  1. 类型检查和转换:当你需要检查对象是否为特定类型,并且希望在同一时间内将其转换为那个类型时,模式匹配提供了一种更简洁的方式来完成这一任务,避免了使用传统的as和is操作符后还需要进行额外的null检查。
  2. 复杂条件逻辑:在处理复杂的条件逻辑时,特别是涉及到多个条件和类型的情况下,使用模式匹配可以使代码更加清晰易读。通过模式匹配,可以将复杂的if-else链或switch语句简化,使逻辑更直观。
  3. 解构复合类型:当你需要从复合类型(如元组、自定义类等)中提取值时,模式匹配允许你直接在条件检查中进行解构,这样可以避免编写额外的解构代码,使得代码更加简洁。
  4. 范围检查:对于需要进行范围检查的场景,如检查一个数是否落在某个区间内,使用C# 9.0引入的关系模式可以极大简化代码,使得范围检查逻辑一目了然。
  5. 逻辑组合:在需要对多个条件进行逻辑组合的情况下,如需要检查一个值是否满足多个条件之一或全部条件,使用逻辑模式可以直接在模式匹配表达式中使用and、or和not运算符,避免了复杂的逻辑嵌套。
  6. 数据验证:模式匹配可以用于数据验证场景,特别是当验证逻辑涉及到类型检查、值范围检查或特定属性值检查时。通过模式匹配,可以在单个表达式中完成所有这些检查,使得验证逻辑更加紧凑和易于维护。
  7. 多态行为:在处理需要根据对象类型执行不同操作的多态行为时,模式匹配提供了一种更灵活的方式来替代传统的虚方法或接口实现。这使得在不修改原有类层次结构的情况下,能够更容易地扩展或修改行为。
  8. 替代访问者模式:在实现访问者设计模式时,模式匹配可以作为一种更简洁的替代方案,特别是在处理复杂的对象结构时。通过模式匹配,可以直接在一个地方处理所有类型的情况,而不需要为每种类型创建单独的访问者方法。

模式匹配的这些用途展示了它在简化代码、提高可读性和灵活处理不同类型和条件的强大能力。随着C#语言的发展,模式匹配的功能和应用场景将会进一步扩展和深化。

下面我们看下一些经典的模式匹配编码风格:

is断言 变量str已被安全地转换为string类型

object obj = "Hello, World!";
if (obj is string str) {
    Console.WriteLine(str);
}

is对可空类型的断言

public record Person(int Id, string? Name, bool? IsActived);
var person = new Person(1, "vipwan", null);
if (person?.IsActived is true)
{
    Console.WriteLine($"Id {person.Id} 已激活");
}

switch 允许使用多种模式,包括类型模式、常量模式和var模式 ,无需我们提前做转换以节省编码量

switch (obj) {
    case 0:
        Console.WriteLine("Zero");
        break;
    case var value:
        Console.WriteLine($"Value: {value}");
        break;
}

switch 中使用弃元_代替变量

public static string CronEveryNHours(this int n) => n switch
{
	(>= 1 and < 24) => $"0 0/{n} * * *",
	_ => throw new ArgumentException("n must be between 1 and 24", nameof(n))
};

C# 8.0引入了属性模式,允许基于对象的属性进行模式匹配

public record Person(string Name,int Age);
var person = new Person("vipwan", 30);
//通俗易懂:如果person不为null,且name==vipwan 并且age>=18的时候
if (person is { Name: "vipwan", Age: >= 18 }) {
    Console.WriteLine("vipwan is an adult.");
}

C# 9.0引入的逻辑模式,它允许使用逻辑运算符andornot来组合模式。

if (number is > 0 and < 10 or 100) {
    Console.WriteLine("Number is between 0 and 10 or equals 100.");
}

元组模式允许你对元组的元素进行模式匹配,这在处理元组返回值或多值情况时非常有用

var numbers = (1, "one", 18);
if (numbers is (1, string name, int age)) {
    Console.WriteLine($"The name of 1 is {name}, age {age}!");
}

列表模式允许对数组、列表等集合进行模式匹配,可以匹配集合的长度、元素等属性。这对于处理集合数据时进行模式匹配提供了极大的便利。

int[] numbers = { 1, 2, 3 };
if (numbers is [1, 2, 3]) {
    Console.WriteLine("The array contains the numbers 1, 2, and 3 in that order.");
}

切片模式允许你匹配集合的一部分,而不是整个集合。这在你只关心集合的某个特定部分时特别有用。

int[] numbers = { 0, 1, 2, 3, 4 };
if (numbers is [0, .., 4]) {
    Console.WriteLine("The array starts with 0 and ends with 4.");
}

这里只是介绍了部分好用常见的模式匹配,随着C#语言的逐代增强,可能会有更多的新特性和改进被引入。

Layui select配合input实现可输入,可选择,可搜索_layui selectinput-CSDN博客

mikel阅读(189)

来源: Layui select配合input实现可输入,可选择,可搜索_layui selectinput-CSDN博客

1.前言
今天遇到一个问题,客户要求select框可以自己输入,就是在下拉列表里找不到自己想要的选项就可以自己输入,同时还要支持模糊匹配功能,百度了一下,都是讲select配合input,input覆盖在select上面,同时又不完全盖住select,就可以实现,输入,和选择并存了,但是模糊匹配是一个问题。好了先看一张效果图。

 

 

Video_2018-10-09_150251.gif

 

其实我这里下拉框中有五个选项,111~555.666是没有的这个是自己输入的。
先看html代码

<div class=”layui-col-md4″>
<label class=”layui-form-label”>移交单位<span style=”color:red”>*</span></label>
<div class=”layui-input-block”>
<input type=”text” name=”HandoverCompany” id=”HandoverCompany” class=”layui-input” style=”position:absolute;z-index:2;width:80%;” lay-verify=”required” value=”111″ onkeyup=”search()” autocomplete=”off”>
<select type=”text” id=”hc_select” lay-filter=”hc_select” autocomplete=”off” placeholder=”移交单位全称” lay-verify=”required” class=”layui-select” lay-search>
<option value=”111″>111</option>
<option value=”222″>222</option>
<option value=”333″>333</option>
<option value=”444″>444</option>
<option value=”555″>555</option>
</select>
</div>
</div>
这里代码我就只粘贴部分,其中input的几个style样式简单说一下。

position:absolute 在这里是让input和select在同一位置。
z-index:2 是为了让input在select上面。
width:80% 是为了不盖住select后面的小三角符号,select还可以点击。
autocomplete=”off” 为了不自动填充input框,免得压盖select选项

然后是JS代码。

layui.use([‘form’, ‘layedit’,’upload’], function () {
var form = layui.form
form.on(‘select(hc_select)’, function (data) { //选择移交单位 赋值给input框
$(“#HandoverCompany”).val(data.value);
$(“#hc_select”).next().find(“dl”).css({ “display”: “none” });
form.render();
});

window.search = function () {
var value = $(“#HandoverCompany”).val();
$(“#hc_select”).val(value);
form.render();
$(“#hc_select”).next().find(“dl”).css({ “display”: “block” });
var dl = $(“#hc_select”).next().find(“dl”).children();
var j = -1;
for (var i = 0; i < dl.length; i++) {
if (dl[i].innerHTML.indexOf(value) <= -1) {
dl[i].style.display = “none”;
j++;
}
if (j == dl.length-1) {
$(“#hc_select”).next().find(“dl”).css({ “display”: “none” });
}
}

}
});
简单说一下我的思路,首先select选择的值要能赋值给input框,可以就需要form.on(‘select(hc_select)’来监听select值的变化,选择了之后要把下拉列表给隐藏掉。同时重新渲染一下这个表单,只重新渲染当前的select也是可以的。
然后就是输入到input框里的文字如何去select中去搜索。首先我们通过检查select的dom结构可以发现,他里面的选项都是在dl下的dd标签中,如图。

 

image.png

然后我们获取到dl标签,然后通过循环的方式挨个去匹配dd中的选项与我们输入的文本是否存在关系。通过indexOf就行。如果不相似,则直接隐藏掉,然后这里为什么要定义一个j呢?是因为如果都不匹配的话,下面还是会出来一个空的dl标签,页面显示就是一个空的小列表,有点影响美观,所以如果你输入的文本和下拉列表中的选项都没关系的话,直接把dl给隐藏了。这里我是判断不相似的个数如果和dl.length 相等的话,就说明你输入的文本和select的选项没一个相似的,然后就可以把dl隐藏了。
study hard and make progress every day。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/u012869793/article/details/84453150

Visual Studio 必备插件集合:AI 助力开发 - 小码编匠 - 博客园

mikel阅读(207)

来源: Visual Studio 必备插件集合:AI 助力开发 – 小码编匠 – 博客园

一、前言

2024年AI浪潮席卷全球,编程界迎来全新的挑战与机遇。智能编程、自动化测试、代码审查,这一切都得益于AI技术的迅猛发展,它正在重塑开发者的日常,让编写代码变得更加高效、智能。

精选出最受好评、最具实用价值的Visual Studio插件,涵盖代码编辑、调试、测试、版本控制等多个方面,帮助开发者选择出正确的工具,提升开发效率和质量。无论是初出茅庐的编码新手,还是久经沙场的资深码农,总有一款插件能够满足你的需求,激发你的编程灵感。通过本文的介绍,将能够发现那些隐藏在Visual Studio插件市场中的瑰宝,让它们成为我们日常开发工作中的得力助手。

二、Visual Studio 插件安装指南

Visual Studio 通过安装插件,可以极大地扩展其功能,提高开发效率。无论是初学者还是经验丰富的开发者,都能轻松上手。

步骤一:启动Visual Studio

1、打开 Visual Studio开发工具。

2、如果尚未创建或打开项目,可以选择”创建新项目”或”打开现有项目”来启动Visual Studio,具体如下图所示:

步骤二:访问扩展和更新
在Visual Studio 顶部菜单中,点击”扩展” > “管理扩展”,具体如下图所示:

步骤三:搜索和选择插件

1、点击“管理扩展”标签页,具体如下图所示:2、在搜索框输入你想要安装的插件名称或关键词,例如”Resharper”、”CodeMaid”等。3、浏览搜索结果,查看插件的详细信息,包括描述、评分、评论和版本信息。

步骤四:安装插件

1、找到你需要的插件后,点击右侧的”下载”按钮。

2、下载完成后,按钮会变成”安装”,点击以开始安装过程。3、插件的大小和你的网络速度,安装过程可能需要几分钟时间。4、安装完毕后,可能需要重启Visual Studio才能使插件生效。

步骤五:启用插件

1、重启Visual Studio后,插件应该已经自动启用。

2、如果需要手动启用,可以在”工具”> “扩展和更新”中找到已安装的插件,确保其状态为”已启用”。

3、对于一些插件,可能还需要额外的配置,如设置快捷键或调整选项,这些通常可以在”工具” > “选项”中找到。

三、Visual Studio 如何高效搜索插件

Visual Studio庞大的插件库中提供了一些高效的搜索工具和技巧,可以帮助你快速定位到所需的插件。

1、插件市场

https://marketplace.visualstudio.com

2、使用关键词搜索是最直接的查找方式。在插件市场页面的搜索框中输入关键词,如”TONGYI Lingma”、”Fitten Code”。

3、利用筛选和排序功能,可以根据插件的类型、评级、更新日期等条件进行筛选。

4、点击搜索结果中的插件,可以查看插件的详细信息页面,包括插件的描述、截图、用户评价和版本历史等。

四、Visual Studio AI插件推荐

在Visual Studio中,有几个AI的插件可以帮助提升开发效率和代码质量,推荐实用的AI插件。

1、Fitten Code(免费)

Fitten Code 是由非十大模型驱动的AI编程助手,支持多种编程语言,支持主流几乎所有的IDE开发工具。包括VS Code、Visual Studio、JetBrains系列IDE(包括IntelliJ IDEA、PyCharm等)等,还适配了上古神器VIM。

  • 自动生成代码,提升开发效率。
  • 调试Bug,节省时间。
  • 对话聊天,解决编程问题。

官网文档:https://code.fittentech.com/tutor_vs_zh

2、CodeGeeX (免费)

CodeGeeX 是一款基于大模型的智能编程助手,它可以实现代码的生成与补全、自动为代码添加注释、自动解释代码、自动编写单元测试、实现代码审查Code Review、自动修复代码fixbug、自动生成commit message完成git提交,以及在不同编程语言的代码间实现互译、针对技术和代码问题的智能问答等丰富的功能。

帮助开发者显著提高工作效率,CodeGeeX支持100+种编程语言,适配多种主流IDE平台,包括Visual Studio Code,JetBrains IDEs,Visual Studio,HBuilderX,DeepIn-IDE等。

  • 代码生成与补全。
  • 自动为代码添加注释和解释。
  • 编写单元测试、代码审查(Code Review)。
  • 自动修复代码(fix bug)。
  • 自动生成commit message完成git提交。
  • 跨语言代码互译和智能问答。

官网文档:https://codegeex.cn/

适用场景:适用于需要快速生成代码原型或进行代码重构的场景。

3、通义灵码(个人版免费)

工具提供了AI代码建议和优化,可以帮助开发者更快地理解和编写代码。它已经在Visual Studio Code、和其他IDE中上线,现在也加入了Visual Studio的插件市场。

  • 智能代码补全
  • 代码风格优化
  • 码审查与错误检测
  • 智能问答与文档生成
  • 跨语言支持

官方文档:https://help.aliyun.com/document_detail/2590613.html

4、GitHub Copilot(付费)

GitHub Copilot是一款AI辅助工具,能够帮助开发者更快速、智能地编写高质量代码。

它支持多种编程语言,如Python、JavaScript、TypeScript、Ruby、Go、C#和C++等。

  • GitHub Copilot 会在你编码时提供建议:有时是当前行的补全,有时是全新的代码块。可以接受全部或部分建议,也可以忽略建议并继续键入。
  • 实时提供代码建议,从单行代码到完整函数。
  • 自动为代码添加注释,提高代码可读性。
  • 支持代码补全、解释和审查等功能。

五、Visual Studio 必备插件大全

1、ILSpy-2022(免费)

ILSpy 对于.NET开发者来说是一个宝贵的资源,无论是用于学习、逆向工程还是作为开发过程中的辅助工具。由于其开源性质,ILSpy持续得到社区的支持和更新,保持着与最新.NET版本的兼容性。可以集成在Visual Studio 开发工具中,能够十分快捷方便的查看源代码内容。

2、Visual-Studio-Translator (免费)

Visual-Studio-Translator 是一款专为 Visual Studio 开发者设计的强大翻译工具,在提升开发过程中的语言处理效率。

这款工具通过集成在 Visual Studio 编辑器中,使得开发者能够轻松实现代码、注释以及其他文本内容的即时翻译,极大地促进了跨语言编程和文档处理的便利性。

安装完成后,通过简单的配置即可开始使用。在需要翻译的内容上右键点击并选择”Translate”选项,或使用快捷键触发翻译功能,即可获得翻译结果。

快捷键

  • Google 翻译:(Ctrl + Shift + D, Ctrl + Shift + D)
  • 必应翻译:(Ctrl + Shift + D,ctrl + Shift + F)
  • 百度翻译:(Ctrl + Shift + D,ctrl + Shift + C)
  • 有道翻译:(Ctrl + Shift + D,ctrl + Shift + V)

3、CodeMaid(免费)

CodeMaid是一个功能强大的Visual Studio扩展插件,通过提供自动代码清理、格式化、重构等功能,提高代码质量、提升开发效率并减少错误率。

支持Visual Studio版本:从VS 2005至VS 2022(最新版本主要支持 VS 2019和 VS 2022)

  • 代码整理与格式化:自动整理白色空间,包括缩进、空格、空行等,提供多种格式化方式,支持批量格式化,可选择”保存时自动清理”,实现每次保存代码时自动格式化。
  • 注释整理:自动整理注释内容,去除不必要的换行和空格。调整注释样式,使其更加规范和整洁。
  • 代码重构:按照Microsoft的Style Copy规范或自定义规则重新排列成员。自动创建匹配的区域,优化代码结构。
  • 代码审查:在代码审查过程中,帮助识别潜在的问题和不规范的代码。
  • 其他辅助功能:支持多行代码合并为一行,按字母排序代码,删除已选的#region。一键折叠解决方案和快速定义文档在解决方案的位置。

4、CSharpier(免费)

CSharpier 是一个开源、免费且轻量级的 C# 代码格式化工具,它基于 Roslyn 编译器框架来解析和重新格式化 C# 代码。

这个工具的设计目的是使代码风格保持一致,从而提高代码的可读性和可维护性。

  • 智能格式化:使用 Roslyn 编译器框架深入理解 C# 语法结构,从而做出更加智能的格式决策。
  • 高度定制化:虽然设计哲学倾向于提供有限的选项,但 CSharpier 仍允许一定程度的定制,以满足不同团队的需求。
  • 无缝集成:支持多种集成开发环境(IDE),如 Visual Studio(2019和2022版本)、Visual Studio Code 等,可以在这些环境中实现保存时自动格式化代码。

提供有限但关键的选项,确保代码格式的一致性,减少开发者在代码风格上的争论。

5、XAML Styler for Visual Studio 2022(免费)

XAML Styler for Visual Studio 2022 是一款专为Visual Studio 2022设计的免费扩展插件,帮助开发者格式化XAML代码,提升代码的可读性和一致性。

  • 自动化格式化:支持多种格式化选项,如属性排序、换行规则、空格处理等。
  • 提高可读性:通过格式化,XAML代码变得更加清晰、易于阅读和理解。
  • 灵活配置:用户可以根据自己的偏好和需求配置XAML Styler的格式化选项。
  • 集成到Visual Studio:XAML Styler无缝集成到开发环境中。
  • 支持多种XAML相关文件:不仅限于标准的XAML文件,还可能支持其他与XAML相关的文件类型,如XAML资源字典等。

6、Indent Guides for VS 2022(免费)

Indent Guides 是一个流行的 Visual Studio 插件,用于改善代码阅读性和可维护性。这个插件的主要功能是在代码编辑器中添加垂直引导线,这些引导线帮助开发者视觉上对齐代码块,尤其是那些与大括号 {} 相关的代码块。

以下是 Indent Guides 插件的一些关键特性和优势:

  • 垂直引导线:插件在每个代码块的左侧添加细线,这些线与大括号 {} 对齐,帮助开发者直观地看到哪些代码属于同一代码块。这在处理嵌套结构时尤其有用。
  • 增强代码结构的可见性:引导线提高了代码结构的清晰度,使开发者能够迅速识别出代码块的开始和结束位置,即使是在长文件中。
  • 提升代码可读性:通过视觉辅助,Indent Guides 可以帮助减少代码阅读时的认知负荷,使得代码更容易理解和维护。
  • 适用于多种语言:插件支持多种编程语言,包括 C#, VB.NET, C++, JavaScript, TypeScript 等,只要这些语言使用大括号来界定代码块。
  • 自定义选项:开发者可以根据个人偏好调整引导线的颜色和可见性。例如,可以选择在代码编辑器中总是显示引导线,或者仅在代码折叠时显示。
  • 安装和使用:Indent Guides 可以直接从 Visual Studio 的扩展管理器中搜索并安装。一旦安装,它会自动应用于所有支持的语言项目中,但在某些情况下可能需要重启 Visual Studio 才能使更改生效。
  • 开源性质:Indent Guides 是一个开源项目,这意味着它可以免费使用,并且开发者社区可以贡献代码来改进插件。

7、Viasfora(免费)

Viasfora是一个功能强大的工具,既可以作为Visual Studio的免费扩展来改善文本编辑体验,也可以作为Python中的可视化编程库来创建交互式图形和可视化。根据不同的应用场景和需求,Viasfora提供了丰富的功能和自定义选项,以满足开发者的不同需求。

  • 彩虹括号:这是Viasfora最为著名的功能之一,它通过使用不同的颜色来区分嵌套的大括号、小括号和方括号,从而帮助开发者更清晰地跟踪代码结构。
  • 关键字高亮:Viasfora能够高亮显示编程语言中的关键字,如流程控制关键字(if、for、while等)和LINQ查询关键字,提高代码的可读性。

  • 其他功能:包括自动展开折叠的区域、演示模式、转义序列和格式说明符的高亮等。

开发者可以通过Visual Studio的“选项 – 环境 – 字体和颜色”或Viasfora自身的设置界面来自定义关键字的颜色、彩虹括号的颜色深度等。

8、SQL Search(免费)

SQL Search 是由 Redgate 软件公司开发的一款 SQL Server Management Studio (SSMS) 和 Visual Studio 的插件,其主要功能是在 SQL Server 数据库中快速搜索 SQL 代码和文本。

它极大地提高了数据库开发和管理的效率,尤其是在大型项目中,其中可能包含数千个数据库对象和数百万行的 SQL 代码。

以下是 SQL Search 插件的一些关键特点:

  • 快速搜索:SQL Search 提供了快速搜索 SQL 代码的能力,能够在数据库、存储过程、函数、视图、触发器以及注释中查找特定的文本或模式。
  • 跨数据库搜索:它允许你同时在多个数据库中进行搜索,这在需要跨多个数据库环境查找相似代码或模式时特别有用。
  • 智能搜索:插件支持正则表达式和通配符,可以进行更复杂的搜索模式匹配。
  • 即时反馈:在输入搜索条件的同时,搜索结果会立即显示,无需等待完整的搜索过程完成。
  • 结果预览:搜索结果中可以直接预览匹配的代码片段,无需打开每一个对象来查看。
  • 结果导航:你可以从搜索结果中直接跳转到具体的数据库对象,便于修改和审查代码。
  • 历史记录与书签:SQL Search 记录搜索历史,并允许保存常用的搜索项作为书签,以便将来快速重复使用。
  • 轻量级与高性能:插件设计得十分轻巧,不会显著影响 SSMS 或 Visual Studio 的性能。
  • 无缝集成:它紧密地与 SSMS 和 Visual Studio 集成,提供一致的用户界面和流畅的工作流。
  • 版本控制友好:对于版本控制系统中的代码更改,SQL Search 也能提供有效的搜索和比较功能。

9、EFCore.Visualizer(免费)

EFCore.Visualizer 是一个专为 Microsoft Visual Studio 设计的免费插件,用于增强 Entity Framework Core (EF Core) 的开发体验。它的主要功能是提供一个可视化工具,让开发者能够直观地查看和理解 EF Core 查询计划,这对于调试和优化数据库查询性能至关重要,支持SQL Server和PostgreSQL两个数据库。

  • 查询计划可视化:这个插件使得在 Visual Studio 中直接查看和分析 EF Core 的 LINQ 查询转换成的 SQL 查询成为可能。通过图形化界面展示查询树,开发者可以更容易地识别查询中的瓶颈或低效部分。
  • 调试支持:当你在代码中设置断点并运行调试时,可以在 Watch 窗口中使用此插件来实时观察查询计划的变化。这对于理解运行时的查询行为非常有帮助。
  • 数据库兼容性:EFCore.Visualizer 支持多种数据库系统,包括 SQL Server 和 PostgreSQL,这意味着无论你使用哪种数据库,都可以利用该插件进行查询优化。
  • 易于使用:插件的安装和使用相对简单,可以通过 Visual Studio 的扩展管理器或者插件市场下载并安装。
  • 性能优化:通过识别和优化查询计划,EFCore.Visualizer 可以帮助开发者减少数据库查询的时间,从而提高应用程序的整体性能。

   SQL Server

     PostgreSQL

10、EF Core Power Tools(免费)

EF Core Power Tools 是一个非常有用的 Visual Studio 扩展,专为 Entity Framework Core (EF Core) 开发者设计。它提供了丰富的功能来帮助我们在开发过程中更高效地处理数据库和实体模型。

以下是一些主要的功能:

  • 反向工程(Reverse Engineering):EF Core Power Tools 允许你从现有的数据库中生成 EF Core 的数据访问层代码,包括 DbContext 类和实体模型类。这通常被称为“数据库优先”(Database-First)方法。
  • 数据库迁移管理:它提供了一个图形界面来管理数据库迁移,使你可以轻松创建、应用和回滚迁移。
  • 模型可视化:插件能够生成实体模型的图形表示,这有助于理解模型结构和关系。
  • 代码生成:可以生成 CRUD 方法和其他常用操作的代码模板。
  • CLI 工具:EF Core Power Tools CLI 是一个命令行工具,允许你在不打开 IDE 的情况下执行上述任务,这对于自动化工作流程和持续集成/持续部署 (CI/CD) 流程非常有用。
  • SQL Server DACPAC 支持:如果你使用 SQL Server 并且有 DACPAC 文件,那么你可以直接从 DACPAC 文件生成 EF Core 代码。
  • 连接字符串管理:插件简化了设置和管理连接字符串的过程。
  • 兼容性:支持 EF Core 的多个版本,包括但不限于 6.x 和 8.x 版本。

六、总结

本文介绍了Visual Studio插件的安装与搜索技巧,强调其对提升开发效率的价值。通过精确关键词搜索与用户评价筛选,快速锁定优质插件。

特别推荐AI增强型插件,如Fitten Code,智能代码建议加速开发。精选涵盖代码管理至设计优化的必备工具,全方位升级编程体验,打造高效开发环境。

拯救SQL Server数据库事务日志文件损坏的终极大招 - 桦仔 - 博客园

mikel阅读(180)

来源: 拯救SQL Server数据库事务日志文件损坏的终极大招 – 桦仔 – 博客园

在数据库的日常管理中,我们不可避免的会遇到服务器突然断电(没有进行电源冗余),服务器故障或者 SQL Server 服务突然停掉,

头大的是ldf事务日志文件也损毁了,SQL Server服务器起来之后,发现数据库处于”Recovery Pending” 状态。

更麻烦的是该数据库没有任何备份或者备份已经比较久远;

当然这些都不是最难的,最难的是连资深DBA使出ATTACH_REBUILD_LOG和 DBCC CEHECKDB 的 REPAIR_ALLOW_DATA_LOSS 选项等招数时候,

即使已经做好了最坏打算,做了丢失部分数据的准备,数据库还是无法上线。

 

本文将分享终极处理方法,帮助您成功恢复数据库。

 


 

测试环境: SQL Server 2022,Windows 2016

注意:奇技淫巧有风险,做任何操作之前注意先做备份! 

 

 

模拟环境

首先,在数据库 testdb 中创建 testObject 表,并不停插入所有对象数据。

在窗口一我们运行插入数据脚本,使用多次 CROSS JOIN,以获得足够多的数据,插入数据脚本实际是一个模拟的大事务。

复制代码
--窗口1

CREATE DATABASE testdb
GO
USE testdb
GO        

SELECT * INTO testObject FROM sys.all_objects


--前面脚本执行完成再执行下面的插入语句
INSERT INTO dbo.testObject
SELECT o.* FROM sys.all_objects o
 CROSS JOIN sys.all_objects o1
 CROSS JOIN sys.all_objects o2
 CROSS JOIN sys.all_objects o3
 CROSS JOIN sys.all_objects o4
复制代码

返回信息如下

-- Msg 109, Level 20, State 0, Line 0
--A transport-level error has occurred when receiving results from the server. (provider: Shared Memory Provider, error: 0 - 管道已结束。)

 

在窗口二我们在关闭测试实例时,窗口一的插入事务仍然在运行。

这将使得数据库处于不一致状态,在数据库启动时,执行数据库恢复。

--窗口2
--执行完下面语句之后,移走ldf文件,模拟ldf文件损坏


SHUTDOWN WITH NOWAIT

数据库停服后,将testdb数据库 的ldf事务日志文件改名或者移到其他路径,重新启动SQL Server 服务,可以看到,testdb 数据库处于“恢复挂起”状态。

因为在停服时候,还有未提交的插入事务保存在ldf事务日志文件,需要在数据库启动时候把事务日志捞出来做crash recovery。

数据库启动之前,已经把ldf事务日志文件移动到别的地方

此时,我们已经有一个孤立的,不一致的数据库文件。

现在我们必须先离线数据库,把mdf文件复制到别的地方作为备份,然后删除数据库,为后续的附加ldf事务日志文件做准备

--窗口3

USE master
GO     
ALTER DATABASE [testdb] SET OFFLINE;

把mdf文件复制到别的地方作为备份,因为数据库离线了,并不会删除物理数据文件

--窗口4

USE master
GO     
DROP  DATABASE [testdb] ;

 

传统方法

使用 ATTACH_REBUILD_LOG 来重建ldf事务日志文件

复制代码
--窗口5

USE master
GO    
CREATE DATABASE [testdb] ON
(FILENAME='E:\DataBase\testdb.mdf')
FOR ATTACH_REBUILD_LOG


GO
复制代码

报错信息如下

--文件激活失败。物理文件名称'E:\DataBase\testdb_log.ldf'可能不正确。
--无法重新生成日志,原因是数据库关闭时存在打开的事务/用户,该数据库没有检查点或者该数据库是只读的。如果事务日志文件被手动删除或者由于硬件或环境问题而丢失,则可能出现此错误。
--Msg 1813, Level 16, State 2, Line 8
--无法打开新数据库 'testdb'。CREATE DATABASE 中止。

到此为止,我们很可能只有去找备份文件还原了(如果有的话),否则可能就是一场灾难了。

 


 

新方法
接下来将介绍终极恢复数据库的方法,以帮助您度过劫难。

使用 CREATE DATABASE 语句中非官方文档记载(undocument)的命令,这个命令就是ATTACH_FORCE_REBUILD_LOG

这个命令会强制重建ldf事务日志文件,即使数据库检测到ldf事务日志文件和mdf数据文件之间有不一致的情况。

复制代码
--窗口6

USE master
GO    
CREATE DATABASE [testdb] ON
(FILENAME='E:\DataBase\testdb.mdf')
FOR ATTACH_FORCE_REBUILD_LOG
GO
复制代码

返回信息如下

--文件激活失败。物理文件名称'E:\DataBase\testdb_log.ldf'可能不正确。
--新的日志文件 'E:\DataBase\testdb_log.ldf' 已创建。

数据库虽然恢复正常,但数据表依然无法访问

复制代码
--窗口7

USE [testdb]
GO

SELECT TOP 10 *  FROM [dbo].[testObject]

SELECT COUNT(*)  FROM [dbo].[testObject]
复制代码

报错信息如下

--Msg 824, Level 24, State 2, Line 18
--SQL Server 检测到基于逻辑一致性的 I/O 错误: pageid 不正确(应为 1:69856,但实际为 0:0)。在文件“E:\DataBase\testdb.mdf”中的偏移 0x000000221c0000 处,在数据库 ID 9 中的页面 (1:69856) 的 读取 期间发生。SQL Server 错误日志或操作系统错误日志中的其他消息可能会提供更多详细信息。这是一个威胁数据库完整性的严重错误条件,必须立即更正。请执行完整的数据库一致性检查(DBCC CHECKDB)。此错误可以由许多因素导致;有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2252374。

 

使用最小数据丢失的方式,修复数据库

头两个命令将数据库分别置于紧急模式和单用户模式,这是我们执行 DBCC CHECKDB 的 REPAIR_ALLOW_DATA_LOSS 选项的前提。

最后一句命令是将数据库恢复多用户模式。

复制代码
--窗口8
--使用最小数据丢失的方式,修复数据库

USE [master]
GO 
ALTER DATABASE [testdb] SET EMERGENCY
GO  
ALTER DATABASE [testdb] SET SINGLE_USER WITH NO_WAIT
GO  
DBCC CHECKDB([testdb],REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS



--dbcc checkdb执行完毕之后执行下面语句,让数据库可以重新访问
ALTER DATABASE [testdb] SET MULTI_USER WITH NO_WAIT
复制代码

DBCC CHECKDB返回信息如下,很多信息这里做了省略

可以看到有5924 个一致性错误,修复了 5924 个一致性错误,也就是全部修复了

复制代码
--testdb的 DBCC 结果。

--Msg 8909, Level 16, State 1, Line 19
--表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 ID (1:69830) 在其页头中包含错误的页 ID。页头中的 PageId 为 (0:0)。
--        该错误已修复。
--Msg 8909, Level 16, State 1, Line 19
--表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 ID (1:69831) 在其页头中包含错误的页 ID。页头中的 PageId 为 (0:0)。
--        该错误已修复。
--Msg 8909, Level 16, State 1, Line 19
--data)释放。
--修复: 页 (1:70420) 已从对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data)释放。
--修复: 页 (1:70421) 已从对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data)释放
。。。

--对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data): 无法处理页 (1:69866)。有关详细信息,请参阅其他错误消息。
--        该错误已修复。
--Msg 8928, Level 16, State 1, Line 19
--对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data): 无法处理页 (1:69867)。有关详细信息,请参阅其他错误消息。
--        该错误已修复。

。。。

--sys.filetable_updates_2105058535的 DBCC 结果。
--对象“sys.filetable_updates_2105058535”在 0 页中找到 0 行。
--CHECKDB 在数据库 'testdb' 中发现 0 个分配错误和 5924 个一致性错误。
--CHECKDB 在数据库 'testdb' 中修复了 0 个分配错误和 5924 个一致性错误。
--DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
复制代码

数据库处于单用户模式

 

设置回多用户模式之后,尝试查询数据

复制代码
--窗口9

--从数据行数来看,具体你是不知道丢失多少数据的,只能说能挽救多少是多少吧



USE [testdb]
GO


SELECT TOP 10 *  FROM [dbo].[testObject]

SELECT COUNT(*) AS'rowcount' FROM [dbo].[testObject]
复制代码

数据是查询出来了,但是具体丢失多少数据,我们无法掌握

至少数据库最后一次checkpoint点之后的所有数据将会丢失。

 

 

 


 

总结

 

在传统的方法里面,还有一个方法就是 新建一个同名的空数据库作为傀儡数据库,然后替换傀儡数据库的数据文件

再对傀儡数据库执行DBCC CEHECKDB 的 REPAIR_ALLOW_DATA_LOSS 选项,但是实际上也不能保证100%有效

这个方法网上已经有相关文章,这里就不展开叙述了。

 

 

 

前几天帮一个网友恢复数据库,由于这个网友的数据库没有任何备份,并且遇到ldf事务日志损坏的问题,

起初使用ATTACH_REBUILD_LOG来重建ldf事务日志文件不成功,还有打算借助第三方工具ApexSQL Log,不过因为网友的数据库版本太高

ApexSQL Log工具不支持,幸好在外网刚好搜索到ATTACH_FORCE_REBUILD_LOG这个命令,

最后总算帮这个网友尽最大努力挽回了数据。

 

 

 

最后提醒一下,附加没有ldf事务日志文件的数据库,并重建日志文件,有以下方法,其中有些方法已经废弃

DBCC REBUILD_LOG:已经废弃
sp_attach_single_file_db:已经废弃
ATTACH_REBUILD_LOG:推荐使用
ATTACH_FORCE_REBUILD_LOG:慎用

 

 

 

参考文章

https://www.mssqltips.com/SQLServertip/3579/how-to-attach-a-sql-server-database-without-a-transaction-log-and-with-open-transactions/

SQL SERVER – Unable to Attach Database – File Activation Failure – The Log Cannot be Rebuilt

Recovering master database with corrupted t-log and no backups

 

 

本文版权归作者所有,未经作者同意不得转载。

只会建数据库怎么写API?database2api 能帮到你! - 开发者精选资讯 - 博客园

mikel阅读(246)

来源: 只会建数据库怎么写API?database2api 能帮到你! – 开发者精选资讯 – 博客园

database2api 是一款强大而便捷的工具,主要功能是依据现有的数据库自动生成开放的 API 接口,能够为开发者大幅节省时间与精力,尤其适用于那些已拥有数据库且需要提供 API 接口,或者仅会构建数据库、而需要迅速实现 API 接口的场景。

一、功能介绍

database2api 能够智能地解析数据库结构,并根据用户的需求和配置,自动生成相应的 API 接口,让您无需繁琐的手动编码,即可轻松实现数据库与外部应用的交互。

在当今的软件开发中,数据库与外部应用的交互是至关重要的环节。然而,手动编写 API 接口往往是一项耗时且容易出错的工作,而且需要具备某一种后端编程语言,门槛较高。database2api 的开发旨在解决这一痛点,让开发者能够更专注于业务逻辑的实现,而无需在接口开发上花费过多的时间和精力。

例如,在一个快速发展的项目中,数据库结构可能会频繁变动。使用 database2api ,您只需更新配置文件,即可快速重新生成适应新结构的 API 接口,极大地提高了项目的敏捷性。

无论您是个人开发者还是团队,database2api 都将是您提升开发效率、加速项目进程的得力助手。

二、技术原理

本工具使用 Ktor 作为底层框架,JDBC 作为数据库访问层,通过 java.SQL.DatabaseMetaData 获取到数据库结构,再通过 Ktor 动态注册 API 路由,实现直接由数据库生成 API 接口。

三、目前已支持的数据库

目前,database2api 已支持以下多种主流数据库:

  • SQLite
  • ✅ MySQL
  • ✅ Postgresql
  • ✅ Microsoft SQL Server
  • ✅ MariaDb

四、优势

  1. 高效便捷:通过简单的配置文件,即可快速生成所需的 API 接口,大大提高开发效率。
  2. 广泛的数据库支持:涵盖了常见的数据库类型,满足不同项目的需求。
  3. 易于维护:生成的接口结构清晰,代码规范,便于后续的扩展和测试。

五、如何使用

  • 点击下载 或直接克隆仓库编译为 jar,文件名为 database2api.jar
  • 目录结构预览
│  database2api.jar  <-- 主程序(必选)
└─ data
     └─ ext          <-- 扩展 API 放置目录(可选)
     └─ web          <-- 静态文件目录(可选)
     └─ setting.ini  <-- 配置文件(必选)
  • 配置文件 setting.ini 样例
# API 默认端口
API_PORT=8080
# 生成API的前缀,如设置 api/v1 后,则API变为:http://localhost:{PORT}/api/v1/xxxxxx
API_PREFIX=api
# 是否启用 API 文档,地址 http://localhost:{PORT},设为 false 不会生成 API 文档
API_INDEX_ENABLED=true
# 是否启用接口授权访问功能,默认false,所有 API 无需授权认证即可访问
API_AUTH_ENABLED=false
# 接口授权访问,支持:Basic, JWT。(以后可能会支持其他的授权认证方式)
API_AUTH_TYPE=JWT
# 接口允许访问的用户名密码列表
API_AUTH_USERS=admin:123456,user:1234
# 数据库默认链接地址(主要需要这里的数据库连接字符串,其他数据库连接字符串样例在下方)
DB_URL=jdbc:sqlite://G:/database2api-test/sqlite/fqb.db
# 数据库用户名
DB_USER=
# 数据库密码
DB_PWD=
# 生成API的数据表名称,为空则所有的表都生成API,多个使用英文逗号分割
INCLUDE_TABLES=
# 需要忽略的数据表名称,如果不为空,则指定的表名被过滤,多个使用英文逗号分割
IGNORED_TABLES=
# 是否启用静态网站,启用后,则创建web目录,放入静态资源即可访问
STATIC_WEB_ENABLED=true
# 是否开启扩展API,允许用户使用JS代码使用自定义SQL查询数据库
EXT_API_ENABLED=true
  • 启动方式:
java -jar database2api.jar

启动后控制台日志如下:

2024-07-11 23:43:14.367 [main] DEBUG cn.hutool.log.LogFactory - Use [Slf4j] Logger As Default.
2024-07-11 23:43:14.369 [main] INFO  com.mrhuo.Database2Api - Database2Api: 开始初始化
2024-07-11 23:43:14.382 [main] INFO  com.mrhuo.Database2Api - Database2Api: 开始初始化 API 配置
2024-07-11 23:43:14.431 [main] DEBUG cn.hutool.setting.SettingLoader - Load setting file [D:\work\java\database2api\data\setting.ini]
2024-07-11 23:43:14.444 [main] INFO  com.mrhuo.Database2Api - Database2Api: 静态网站主页[http://127.0.0.1:8080/web/index.html]
2024-07-11 23:43:14.444 [main] INFO  com.mrhuo.Database2Api - Database2Api: 开始初始化数据库
2024-07-11 23:43:14.444 [main] INFO  com.mrhuo.Database2Api - Database2Api: 使用链接字符串[jdbc:sqlite://G:/database2api-test/sqlite/fqb.db]
2024-07-11 23:43:15.236 [main] INFO  com.mrhuo.Database2Api - Database2Api: 获取到所有数据表的表结构
2024-07-11 23:43:15.236 [main] INFO  com.mrhuo.Database2Api - Database2Api: 已保存到文件[D:\work\java\database2api\data\tables.json]
2024-07-11 23:43:15.236 [main] INFO  com.mrhuo.Database2Api - Database2Api: 初始化全部成功
2024-07-11 23:43:15.383 [main] INFO  ktor.application - Autoreload is disabled because the development mode is off.
2024-07-11 23:43:16.241 [main] INFO  ktor.application - Application started in 0.928 seconds.
2024-07-11 23:43:16.242 [main] INFO  ktor.application - Application started: io.ktor.server.application.Application@299266e2
2024-07-11 23:43:16.633 [DefaultDispatcher-worker-1] INFO  ktor.application - Responding at http://127.0.0.1:8080

启动成功后目录结构变为:

│  database2api.jar
└─ data
     │  setting.ini
     │  tables.json      <-- 这是数据库中所有的表名称,下次启动时不会从数据库重新获取,直接使用此文件。如数据库已更新,则删除此文件
     │  table_names.json <-- 这是数据库中所有表结构,下次启动时不会从数据库重新获取,直接使用此文件。如数据库已更新,则删除此文件
     └─ ext              <-- 扩展 API 放置目录(可选)
     └─ web              <-- 静态文件目录(可选)
         └─ index.html   <-- 这是静态网页默认首页

打开浏览器,访问 http://127.0.0.1:8080 ,如果开启了配置 API_INDEX_ENABLED=true,此时界面如下:

端口设置见配置文件 API_PORT=8080

如果设置 API_INDEX_ENABLED=false,则不会显示 API 文档界面。

随便找个测试获取所有数据:http://127.0.0.1:8080/api/DEVICE/all

这里的 DEVICE 是数据库中的表名

再测试分页显示数据:http://127.0.0.1:8080/api/DEVICE/paged

可以看到,仅仅是配置了数据库链接,就自动生成一个完整的可用的API接口,非常方便。

六、接口安全性

现已支持 Basic、JWT 两种授权认证方式,配置如下:

# 是否启用接口授权访问功能
API_AUTH_ENABLED=false
# 接口授权访问,支持:Basic, JWT,
API_AUTH_TYPE=JWT
# 接口允许访问的用户名密码列表
API_AUTH_USERS=admin:123456,user:1234

Basic 授权

  • 需要配置 API_AUTH_ENABLED=true 开启API授权
  • 需要配置 API_AUTH_TYPE=Basic (注意大小写)
  • 需要配置 API_AUTH_USERS=user:pass,user1:pass1,设置允许访问的用户密码对

Basic 授权失败演示

授权失败

Basic 授权成功演示

JWT 授权

  • 需要配置 API_AUTH_ENABLED=true 开启API授权
  • 需要配置 API_AUTH_TYPE=JWT (注意大小写)
  • 需要配置 API_AUTH_USERS=user:pass,user1:pass1,设置允许访问的用户密码对

注意,JWT授权,单独提供了一个用户登录接口,路劲为 /api/api-user-login,前面的 api 前缀,由配置 API_PREFIX 来设置

JWT 验证失败演示

JWT 验证成功演示

JWT 用户登录成功演示

JWT 用户登录失败演示

七、高级内容

扩展 API

扩展 API 简单来说就是写一个JS文件,作为API扩展接口,执行数据库访问,完成API请求的功能。

开启方式,在配置文件里设置 EXT_API_ENABLED=true,并在 data 目录下创建 ext 目录,创建文件 get_hello.js,内容如下:

注意:文件名格式为 {get|post}_{api_name}.js

function main() {
    var name = context.query.name || "no name";
    return "hello " + name;
}

规定函数名 main,重新启动 database2api 后可看到控制台提示:

2024-07-14 17:26:58.380 [main] INFO  com.mrhuo.plugins.RoutingKt - Database2Api.scriptApiRoute: 创建扩展API[GET:/api/ext/hello]成功

访问该API http://127.0.0.1:8080/api/ext/hello?name=mrhuo 时,返回结果如下:

{
  "code": 0,
  "msg": "OK",
  "data": "hello mrhuo"
}

注意:扩展API因为用到了脚本引擎来解释执行脚本代码,性能不是太好,如非必要,请勿过度依赖此功能。

扩展API中目前支持 dbcontext 两个对象。

  • db 对象主要用于数据库查询,提供 db.query(sql)db.queryOne(sql)db.exec(sql) 这三个方法
  • context 对象主要用于当前请求参数的获取,提供 context.uricontext.methodcontext.headerscontext.querycontext.body 五个对象

附1:数据库连接字符串模板

注意如果数据库有密码,还需要配置 DB_USER 和 DB_PWD

  1. Sqlite
DB_URL=jdbc:sqlite://G:/db.db
  1. MySQL
DB_URL=jdbc:mysql://127.0.0.1:3306/db?useSSL=false&serverTimezone=UTC&charset=utf8mb
  1. PostgreSQL
DB_URL=jdbc:postgresql://127.0.0.1:5432/db
  1. Microsoft SQL Server
DB_URL=jdbc:sqlserver://;serverName=rm-abc.sqlserver.rds.aliyuncs.com;port=1433;databaseName=db_cms
  1. MariaDb
jdbc:mariadb://127.0.0.1:3306/mysql?useSSL=false&serverTimezone=UTC&charset=utf8mb4

附2:开源地址

https://github.com/mrhuo/database2api

版权提示

MIT

架构与思维:微服务架构的思想本质 - Hello-Brand - 博客园

mikel阅读(163)

来源: 架构与思维:微服务架构的思想本质 – Hello-Brand – 博客园

我们为什么需要微服务架构,它一定是为了解决我们某些问题才出现了。这篇文章我们讨论下微服务架构模式所解决的问题,带来的挑战,以及他的核心思想本质。

1 早期的服务架构

image
上图是一个典型的服务分层架构:
Client: 调用方是browser web或者App
应用层: 实现计算层的业务逻辑,从上游数据层获取数据,对下游Client返回html/json/File等
数据-缓存层: 提高访问数据的性能
数据-数据库层: 持久化数据层

2 它存在的问题

1. 重装单体模式
如果是电商类型的系统,以上的架构明显需要把 用户登录、商品浏览、下单、结算、支付、订单查询都实现在一个系统里面,实在笨重。

2. 流量和并发量限制
当系统的流量或并发量达到一定的阈值,比如日活跃用户数量超过百万,或者每秒请求数(QPS)达到数千甚至更高时,传统的单体架构可能难以支撑如此高的负载。

3. 迭代频率
如果业务需求变更非常频繁,例如每周两次以上甚至每天都有新的功能需要上线,那么整个系统要全量发布,不论你的模块是不是变更了。难顶哟!

4. 系统难以扩展
当系统需要快速扩展以满足业务增长时,微服务架构可以更容易地实现水平扩展。

4. 耦合度和依赖关系
如果旧系统中的模块之间存在高度的耦合和复杂的依赖关系,这可能导致维护和升级变得困难。

5. 缺失故障隔离和容错能力
如果系统中的某个模块出现故障,是否会影响到整个系统的正常运行?答案是肯定的

3 微服务架构的演进

上面的问题,明显是日益膨胀的功能模块和流量规模对单体架构系统的挑战,如果不优化,将衍生出一系列的问题。
我们可以通过微服务架构演进,对系统逐步的升级。以下是我们在业务实践过程中总结的一些经验,予以参考。

3.1 基于业务逻辑拆分

基于业务逻辑拆分相对好理解一点,典型的单一职责原则,我们将功能相近的业务整合到一个服务颗粒上。

业务领域模型拆分
举一个典型的电商业务例子。电商的业务体系庞大,涉及各方面的细节。但是我们大概能够根据业务的职能做一个拆分,比如阿里的电商中台业务,包含 用户账号子系统、商品子系统、订单子系统、客户子系统、物流子系统 等。
因为职能不同,这些领域之间包含清晰的界限,所以我们可以按照这个方向将服务于不同领域(商品域和订单域)的子系统拆成独立的服务颗粒。如下图:
image

用户群体拆分
根据用户群体做拆分,我们首先要了解自己的系统业务里的用户角色领域是否没有功能耦合,有清晰的领域界限。
比如教育信息化系统,教师的业务场景和学生的业务场景,基本比较独立,而且拆分后流量上有明显的削弱。如下图所示:
image

3.2 基于可扩展拆分

这个需要区分系统中变与不变的部分,不变的部分一般是成熟的、通用的服务功能,变的部分一般是改动比较多、需要不断满足业务迭代扩展性需要的功能。
根据二八原则,系统中经常变动的部分大约只占 20%(如 运营、活动),而剩下的 80% (用户信息、基本商品信息、物流信息 等模块的管理能力和视图界面)基本不变或极少变化。如下图所示:
image

3.3 基于可靠性拆分

核心模块拆分
我们团队在做MySQL数据库和Redis集群拆分的时候,总会把一些重要的模块独立放在一个集群上,不与其他模块混用,而这个独立的集群,服务机性能要是最好的。这样做的目的是,当重要度较低的模块发生故障时,不会影响重要度高的模块。同样的道理,我们将账号、支付等核心服务单独拆分在一个服务颗粒上,建立独立服务集群,保证资源独享,来提升可用性。 如下图所示:
image

主次链路拆分
在各个业务系统中,其实都会有主次业务链路。主业务链条,完成了业务系统中最核心的那部分工作。而次链路是保证其他基础功能的稳定运行。
以电商为例子:商品搜索->商品详情页->购物车模块->订单结算->支付业务,就是一条最简单的主链路。主链路是整个系统的核心主战场,最好的资源跟火力都要放在这里,保证不失守。
image
这样的拆分模式保障了核心链路的计算资源分配优先、异常容错处理优先、服务隔离保护等等。

3.4 基于性能需求拆分

根据性能需求来进行拆分。简单来说就是访问量特别大,访问频率特别高的业务,又要保证高效的响应能力,这些业务对性能的要求特别高。比如积分竞拍、低价秒杀、限量抢购。
我们要识别出某些超高并发量的业务,尽可能把这部分业务独立拆分出来。
image

4 代价

分布式系统的固有复杂性
微服务架构是基于分布式的系统,而构建分布式系统必然会带来额外的性能开销和可靠性挑战。
服务的依赖管理和测试
在单体应用中,通常使用集成测试来验证依赖是否正常。而在微服务架构中,单元测试和整条服务链路的可用性都需要关注。
有效的配置版本管理
需要引入配置的版本管理、环境管理。
自动化的部署流程
有效地构建自动化部署体系,配合服务网格、容器技术,是微服务面临的另一个挑战。
对于DevOps有更高的要求
开发者也需承担起整个服务的生命周期的责任,包括部署、链路追踪、监控。构建全功能的团队,也是一个不小的挑战。
运维成本飙升
运维主要包括配置、部署、监控与告警和日志收集四大方面。微服务架构中,每个微服务粒度都需要独立地配置、部署、监控和收集日志,成本呈指数级增长。服务化粒度越细,运维成本越高。

5 微服务架构思想本质

最终的微服务架构可能是这种状态:
image

所以我们可以看出微服务架构的本质应该有如下几个:

  • 风险隔离: 高度自治和高度隔离,明显不让低等级的服务影响高等级
  • 分治原理: 单个服务的吞吐始终是有限的,通过微服务拆分可以突破扩展上限,分拆流量可支撑全球化的业务,不再受机房规模甚至地域影响
  • 单一职责: 单体系统逐渐演变成具有单一职责的细粒度微服务

算法金 | 秒懂 AI - 深度学习五大模型:RNN、CNN、Transformer、BERT、GPT 简介 - 算法金「全网同名」 - 博客园

mikel阅读(199)

来源: 算法金 | 秒懂 AI – 深度学习五大模型:RNN、CNN、Transformer、BERT、GPT 简介 – 算法金「全网同名」 – 博客园

1. RNN(Recurrent Neural Network)

时间轴

1986年,RNN 模型首次由 David Rumelhart 等人提出,旨在处理序列数据。

关键技术

  • 循环结构
  • 序列处理
  • 长短时记忆网络(LSTM)和门控循环单元(GRU)

核心原理

RNN 通过循环结构让网络记住以前的输入信息,使其能够处理序列数据。每个节点不仅接收当前输入,还接收前一个节点的输出,从而形成记忆能力。

创新点

RNN 的创新点在于其循环结构,这使其能处理时间序列数据。但原始 RNN 容易出现梯度消失问题,后来的 LSTM 和 GRU 模型通过引入门控机制,极大地改善了这一问题。

适用数据

  • 时间序列数据
  • 语音信号
  • 文本数据

应用场景

  • 语言模型
  • 语音识别
  • 时间序列预测

经典案例

苹果的 Siri 和 Google 的语音助手都使用了基于 RNN 的技术来进行语音识别和处理。

2. CNN(Convolutional Neural Network)

时间轴

1989年,CNN 由 Yann LeCun 等人提出,主要用于图像处理。

关键技术

  • 卷积层
  • 池化层
  • 全连接层

核心原理

CNN 通过卷积层提取图像的局部特征,池化层进行降维处理,全连接层最终进行分类。卷积操作通过滤波器在图像上滑动,捕捉不同的特征。

创新点

CNN 的创新点在于卷积层的使用,使其能够有效提取图像的空间特征,大大减少了参数数量,提高了计算效率。

适用数据

  • 图像数据
  • 视频数据

应用场景

  • 图像分类
  • 物体检测
  • 图像生成

经典案例

LeNet-5 是最早的 CNN 之一,被用来进行手写数字识别,并取得了显著的成果。

3. Transformer

时间轴

2017年,Google 发布了 Transformer 模型,极大地提升了自然语言处理的效率。

关键技术

  • 自注意力机制
  • 编码器-解码器架构
  • 多头注意力机制

核心原理

Transformer 通过自注意力机制,可以在处理序列数据时并行计算,从而大大提升了效率。编码器处理输入序列,解码器生成输出序列,自注意力机制使得模型能够关注到序列中的重要信息。

创新点

Transformer 摒弃了传统 RNN 的循环结构,通过自注意力机制和并行处理,实现了更快的训练速度和更好的效果。

适用数据

  • 文本数据
  • 语言数据

应用场景

  • 机器翻译
  • 文本生成
  • 情感分析

经典案例

Google 的神经机器翻译系统(GNMT)使用了 Transformer 技术,实现了高质量的机器翻译。

4. BERT(Bidirectional Encoder Representations from Transformers)

时间轴

2018年,Google 发布了 BERT 模型,大大提升了自然语言处理任务的表现。

关键技术

  • 双向编码器
  • 预训练和微调
  • 掩码语言模型

核心原理

BERT 通过双向编码器同时考虑上下文信息,使用掩码语言模型在预训练阶段预测被掩盖的词语,然后进行任务特定的微调。

创新点

BERT 的创新在于其双向性和预训练方法,使得模型在各种 NLP 任务中都表现优异,尤其是在需要上下文理解的任务中。

适用数据

  • 文本数据

应用场景

  • 问答系统
  • 文本分类
  • 命名实体识别

经典案例

Google 搜索引擎在 2019 年开始使用 BERT 来理解用户查询,提高搜索结果的相关性。

5. GPT(Generative Pre-trained Transformer)

时间轴

2018年,OpenAI 发布了 GPT 模型,此后不断迭代,GPT-2 和 GPT-3 进一步提升了文本生成能力。

关键技术

  • 自回归语言模型
  • 预训练和微调
  • 大规模训练数据

核心原理

GPT 通过自回归方式生成文本,使用大量数据进行预训练,然后在特定任务上微调。模型基于 Transformer 架构,能够生成高质量的连贯文本。

创新点

GPT 的创新在于其生成能力和规模,通过预训练和大规模数据,能够生成自然流畅的文本,几乎达到人类水平。

适用数据

  • 文本数据

应用场景

  • 文本生成
  • 对话系统
  • 内容创作

经典案例

OpenAI 的 GPT-3 已经被广泛应用于各种文本生成任务,如代码生成、新闻撰写和对话机器人。以上便是 RNN、CNN、Transformer、BERT 和 GPT 五大深度学习模型的简介。它们各自在不同领域中展现了强大的能力和广泛的应用,推动了人工智能技术的发展和应用。

C# winform 发布的时候没有app.config去哪儿了?_c# app.config 编译后不见-CSDN博客

mikel阅读(155)

来源: C# winform 发布的时候没有app.config去哪儿了?_c# app.config 编译后不见-CSDN博客

有时候winform发布的时候app.config不见了?

1、我们来到生成文件的目录下

找到后缀是 .config 的文件
右击,打开,也可以用其他方式打卡,我这里使用的是sublime这个文本编辑器打开的

打开后:

 

是不是和我们的 app.config 内容一样呀,还有很多初学的小伙伴会问这个东西,有什么用,我们这个东西,就是配置文件,通过读取配置文件的方式可以减少更改程序,有很多东西,我们就可以不用写死在程序里面了, 比如数据库连接字符,以后更换数据库后就可以直接更改我们的连接字符就可以了,这样就不用每次都要变成程序重新发布给别人用了。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_36051316/article/details/83790071

使用ML.NET训练一个属于自己的图像分类模型,对图像进行分类就这么简单! - 追逐时光者 - 博客园

mikel阅读(186)

来源: 使用ML.NET训练一个属于自己的图像分类模型,对图像进行分类就这么简单! – 追逐时光者 – 博客园

前言

今天大姚给大家分享一个.NET开源、免费、跨平台(支持Windows、Linux、macOS多个操作系统)的机器学习框架:ML.NET。并且本文将会带你快速使用ML.NET训练一个属于自己的图像分类模型,对图像进行分类。

ML.NET框架介绍

ML.NET 允许开发人员在其 .NET 应用程序中轻松构建、训练、部署和使用自定义模型,而无需具备开发机器学习模型的专业知识或使用 Python 或 R 等其他编程语言的经验。该框架提供从文件和数据加载的数据。数据库,支持数据转换,并包含许多机器学习算法。

AI和机器学习有什么区别?

AI 是一个计算分支,涉及训练计算机执行通常需要人类智能的操作。机器学习是 AI 的一部分,它涉及计算机从数据中学习和在数据中发现模式,以便能够自行对新数据进行预测。

ML.NET支持的.NET框架

目前ML.NET支持.NET、.NET Core (版本 2.0 及更高版本)和 .NET Framework (版本 4.6.1 及更高版本)。

框架源代码

ML.NET官方提供的使用示例

ML.NET使用环境安装

安装本机.NET环境

首先需要准备好本机的.NET开发环境:

Visual Studio环境配置

选择.NET 桌面开发工作负荷以及可选的 ML.NET Model Builder 组件。

ML.NET Model Builder 组件介绍:提供易于理解的可视界面,用于在 Visual Studio 内生成、训练和部署自定义机器学习模型。

创建一个WinForms应用

创建一个名为:MLNETExercise的.NET8 WinForms应用。

准备好需要训练的图片

训练图像分类模型

测试训练模型的分析效果

在WinForms中调用图像分类模型

调用完整代码

        private void Btn_SelectImage_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Title = "Select Image";
                openFileDialog.Filter = "Image Files (*.jpg, *.png, *.bmp)|*.jpg;*.png;*.bmp|All Files (*.*)|*.*";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    // 获取用户选择的文件路径
                    string selectedImagePath = openFileDialog.FileName;

                    // 从文件加载图片
                    Image img = Image.FromFile(openFileDialog.FileName);
                    this.pictureBox.Image = img;

                    var imageBytes = File.ReadAllBytes(selectedImagePath);
                    MLImageAnalysis.ModelInput sampleData = new MLImageAnalysis.ModelInput()
                    {
                        ImageSource = imageBytes,
                    };

                    //Load model and predict output
                    var result = MLImageAnalysis.Predict(sampleData);
                    this.txt_Box.Text = result.PredictedLabel;
                }
            }
        }

运行效果展示

项目源码地址

更多项目实用功能和特性欢迎前往项目开源地址查看👀,别忘了给项目一个Star支持💖。

优秀项目和框架精选

该项目已收录到C#/.NET/.NET Core优秀项目和框架精选中,关注优秀项目和框架精选能让你及时了解C#、.NET和.NET Core领域的最新动态和最佳实践,提高开发工作效率和质量。坑已挖,欢迎大家踊跃提交PR推荐或自荐(让优秀的项目和框架不被埋没🤞)。

DotNetGuide技术社区交流群

  • DotNetGuide技术社区是一个面向.NET开发者的开源技术社区,旨在为开发者们提供全面的C#/.NET/.NET Core相关学习资料、技术分享和咨询、项目框架推荐、求职和招聘资讯、以及解决问题的平台。
  • 在DotNetGuide技术社区中,开发者们可以分享自己的技术文章、项目经验、学习心得、遇到的疑难技术问题以及解决方案,并且还有机会结识志同道合的开发者。
  • 我们致力于构建一个积极向上、和谐友善的.NET技术交流平台。无论您是初学者还是有丰富经验的开发者,我们都希望能为您提供更多的价值和成长机会。

欢迎加入DotNetGuide技术社区微信交流群👪