智能SQL生成:后端技术与LLM的完美结合

文章目录

  • 引言
  • 一、什么是大模型
  • 二、为什么选择LLM
  • 三、开发技术说明
  • 四、系统架构说明
  • 五、编码实战
    • 1. Maven
    • 2. 讯飞大模型配置类
    • 3. LLM相关的封装
    • 4. 编写LLM的service
    • 5. 编写controller
    • 6. 运行测试
  • 六、总结

引言

本篇文章主要是关于实现一个类似Chat2DB的根据自然语言生成SQL的简单Demo,根据此Demo可以入门大模型应用开发,结合大模型开发出属于自己的大模型应用,让自己的应用智能化,可以根据用户不同问题做出不同的回答。

image-20240225175115184

一、什么是大模型

如果各位有关注一些技术文章,难免会注意到这几年有一个词非常火,没错这就是“大模型”!

那大模型是什么?有什么用呢?

“大模型”是可以指任何规模较大、参数众多的机器学习模型,不仅限于自然语言处理(NLP),也可以包括计算机视觉、语音识别等其他领域的模型。大模型的特点是它们通常需要大量的数据来训练,以及相对较大的计算资源。

大模型的用途十分广泛,在很多领域都有不错的应用价值:

  1. 自然语言的生成和理解:大模型可以根据用户的问题生成连贯的文本回答、或是总结某些文章。ChatGPT就是一个不错的例子。
  2. 图像的处理:例如OpenAI的DALL·E模型,它可以根据用户问题,生成新的图像。
  3. 语言的识别和生成:大模型可以将文本信息转化为人类的语言。
  4. 推荐系统:大模型可以根据用户的行为或某些数据,推测用户的行为爱好,实现个性化推荐。

大模型的应用十分广泛,除了上面举的例子外,还有很多例子,这里就不一一举例了。

61b63d3c-3.png

下面我会使用大模型的其中一种**大型语言模型(Large Language Model,简称LLM)**开发出一些简单的应用Demo,读者可以根据这样的思路进一步完善。

在此之前,先来介绍一下LLM是何物。LLM是指专门用来处理和理解自然语言的大型机器学习模型,LLM通常通过在大量文本数据上进行预训练来学习语言的结构和语义,从而能够执行各种语言处理任务,如文本生成、翻译、摘要、问答和情感分析等。


二、为什么选择LLM

LLM大模型是一款专注于理解和生成自然语言的大模型,那我们系统中无论是Redis还是MySQL的数据,都是文本形式的,将这些文本信息的数据交与大模型处理,能够有针对性地获取到我们想要的数据。

其次,LLM的使用成本较低,国内的大模型无论是讯飞星火大模型还是其他互联网厂商自研的大模型都为开发者提供了不少的免费Token,使得学习成本大大降低。

LLM大模型也是我们大部分人群目前接触最多的大模型,学习成本大幅度降低,只需要知道如何和大模型进行聊天即可懂得如何开发,不需要任何额外的学习成本。

img


三、开发技术说明

本文使用的大模型为讯飞星火大模型,但是咱们不限于任何厂商的大模型,有能力的ChatGPT也可以,作者只是觉得讯飞星火大模型送的Token比较多,非常适合初学者。

读者需要自行前往讯飞星火认知大模型-AI大语言模型-星火大模型-科大讯飞 (xfyun.cn)进行领取免费Token,领取教程这里就不多讲了,网上大把教程,不懂的可以下面留言。

其次,该教程后端方面需要懂得使用SpringBoot进行开发,也就是简单的一个接口开发,没有任何的前端。

最后,开发出来的Demo只是一个抛砖引玉的作用,开发过程中不会考虑太多的规范和其他一些限制,只是单纯把一个小功能实现,代码量也不多,一千行不到。

如果这些都准备好了,那么下面开始发车。


四、系统架构说明

本篇文章会带大家结合后端技术与讯飞星火大模型实现实现根据用户的自然语言问题生成SQL的工具。

自然语言生成SQL?是不是很熟悉,没错,这里是参考了阿里开源的Chat2DB数据库管理功能,不过这里是作者对这个功能自主实现的Demo,没有翻阅过Chat2DB源码,故这里的实现可能并不是Chat2DB的底层实现原理

有能力的可以自己去看看源码:Chat2DB: Chat2DB 是一款有开源免费的多数据库客户端工具,支持windows、mac本地安装,也支持服务器端部署,web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2DB集成了AIGC的能力,能够将自然语言转换为SQL,也可以将SQL转换为自然语言,可以给出研发人员SQL的优化建议,极大的提升人员的效率,是AI时代数据库研发人员的利器,未来即使不懂SQL的运营业务也可 (gitee.com)

怎么根据用户的自然语言描述生成用户想要的SQL呢?下面我们来分析分析

image-20240225172301437

  1. 首先,用户发送一个包含数据库host、user、password、table、用户问题的请求给后端
  2. 后端根据用户提供的数据库信息,连接数据库查询出该表的DDL
  3. 后端与LLM建立连接,将DDL、用户问题、prompt发送给LLM
  4. LLM根据后端提供的数据以及问题,推测分析并生成SQL,将SQL返回给后端
  5. 后端将SQL返回响应给用户

也就是说,后端需要获取并整理数据,然后与LLM建立连接,将数据发送给LLM,LLM再根据数据做出回答,返回给后端SQL,这样就实现了自然语言生成SQL


五、编码实战

了解了整体架构是如何之后,我们进入了编码实战阶段,编码整体来说比较简单,重要的理解整体的架构


1. Maven

构建SpringBoot项目,引入一些我们需要的Maven依赖

    <dependencies><!-- SpringBoot Web容器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version></dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.12.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--okhttp3--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.43</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version> <!-- 根据你需要的版本进行调整 --></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

2. 讯飞大模型配置类

为了方便维护,需要将讯飞星火大模型配置成一个类,方便日后维护

并根据接口文档的内容生成鉴权信息

星火认知大模型Web API文档 | 讯飞开放平台文档中心 (xfyun.cn)

@ConfigurationProperties("xun-fei.xing-huo")
@Component
@Data
public class XFLlmConfig {private String appId;private String domain;private String wsUrl;private String role;private String host;private String path;private String apiSecret;private String apiKey;private Long maxResponseTime;private String prompt;public String getWsUrl() {try {String httpUrl = wsUrl.replaceAll("wss", "https");Date date = new Date();SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);sdf.setTimeZone(TimeZone.getTimeZone("GMT"));String formatData = sdf.format(date);String tmp = "host: " + host + "\n";tmp += "date: " + formatData + "\n";tmp += "GET " + path + " HTTP/1.1";Mac mac = Mac.getInstance("hmacsha256");SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");mac.init(spec);byte[] hexDigits = mac.doFinal(tmp.getBytes(StandardCharsets.UTF_8));// Base64加密String sha = Base64.getEncoder().encodeToString(hexDigits);String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);// 拼接地址HttpUrl url = Objects.requireNonNull(HttpUrl.parse(httpUrl)).newBuilder().addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).addQueryParameter("date", formatData).addQueryParameter("host", host).build();return url.toString().replace("http://", "ws://").replace("https://", "wss://");} catch (Exception e) {throw new RuntimeException("getWsUrl 发生异常");}}}

application.yml

xun-fei:xing-huo:appId: 你的appIddomain: xxxxwsUrl: wss://${xun-fei.xing-huo.host}${xun-fei.xing-huo.path}role: userapiSecret: xxxxapiKey: xxxxhost: spark-api.xf-yun.compath: /v3.5/chat#  30smaxResponseTime: 30000prompt: '下面是一些表的DDL语句, 请严格根据这些DDL语句结合用户的问题为用户生成所需的SQL: \n%s \n用户问题是: %s\n注意只需要回复SQL即可!'

3. LLM相关的封装

下面的request以及response都是参考的接口文档封装的,需要自己看看文档。

请求LLM的Request封装

@Data
public class XFLlmRequest {@JsonProperty("header")private Header header;@JsonProperty("parameter")private Parameter parameter;@JsonProperty("payload")private Payload payload;@Data@Builderpublic static class Header {@JsonProperty("app_id")private String appId;@JsonProperty("uid")private String uid;}@Data@Builderpublic static class Parameter {@JsonProperty("chat")private Chat chat;}@Data@Builderpublic static class Chat {@JsonProperty("domain")private String domain;@JsonProperty("temperature")private Double temperature;@JsonProperty("max_tokens")private Long maxTokens;}@Data@Builderpublic static class Payload {@JsonProperty("message")private Message message;}@Data@Builderpublic static class Message {@JsonProperty("text")private List<Text> text;}@Data@Builderpublic static class Text {@JsonProperty("role")private String role;@JsonProperty("content")private String content;}
}

响应体封装

@Data
public class XFLlmResponse {@JsonProperty("header")private Header header;@JsonProperty("payload")private Payload payload;@Datapublic static class Header {@JsonProperty("code")private Long code;@JsonProperty("message")private String message;@JsonProperty("sid")private String sid;@JsonProperty("status")private Long status;}@Datapublic static class Payload {@JsonProperty("choices")private Choices choices;}@Datapublic static class Choices {@JsonProperty("status")private Long status;@JsonProperty("seq")private Long seq;@JsonProperty("text")private List<Text> text;}@Datapublic class Text {@JsonProperty("content")private String content;@JsonProperty("role")private String role;@JsonProperty("index")private Long index;}
}

WebSocketListener的具体实现,用于收集llm返回的结果

@Slf4j
public class XFWebSocketListener extends WebSocketListener {/*** 断开websocket标志位*/@Getterprivate volatile boolean wsCloseFlag = false;/*** 锁*/@Getterprivate final Object lock = new Object();/*** 语句组装buffer,将大模型返回结果全部接收,在组装成一句话返回*/private StringBuilder answer = new StringBuilder();public String getAnswer() {return answer.toString();}@Overridepublic void onOpen(WebSocket webSocket, Response response) {super.onOpen(webSocket, response);log.info("讯飞星火大模型连接成功!");}@Overridepublic void onMessage(WebSocket webSocket, String text) {synchronized (lock) {super.onMessage(webSocket, text);XFLlmResponse response = JSON.parseObject(text, XFLlmResponse.class);log.info("response:{}", JSON.toJSONString(response));if (response.getHeader().getCode() != 0) {log.error("发生错误,错误信息为:{}", JSON.toJSONString(response.getHeader()));answer.append("大模型响应异常,请联系管理员");// 关闭连接标识wsCloseFlag = true;lock.notify();return;}List<XFLlmResponse.Text> textList = response.getPayload().getChoices().getText();for (XFLlmResponse.Text temp : textList) {log.info("讯飞大模型返回结果信息为:{}", JSON.toJSONString(temp));answer.append(temp.getContent());}log.info("result:{}", answer.toString());if (response.getHeader().getStatus() == 2) {wsCloseFlag = true;log.info("wsCloseFlag为:{}", wsCloseFlag + " result: " + answer);webSocket.close(1000, "Closing WebSocket connection");lock.notify();}}}@Overridepublic void onFailure(WebSocket webSocket, Throwable t, Response response) {super.onFailure(webSocket, t, response);try {if (null != response) {int code = response.code();assert response.body() != null;log.error("onFailure body:{}", response.body().string());if (101 != code) {log.error("讯飞星火大模型连接异常");}}} catch (IOException e) {log.error("IO异常:" + e);}}@Overridepublic void onClosing(WebSocket webSocket, int code, String reason) {super.onClosing(webSocket, code, reason);wsCloseFlag = false;answer = new StringBuilder();}
}

4. 编写LLM的service

LLMService提供两个方法,一个是sendMsg用于给LLM发送数据,getResult则是获取LLM的响应结果

@Service
@Slf4j
public class LlmServiceImpl implements LlmService {@Resourceprivate XFLlmConfig xfLlmConfig;@Overridepublic WebSocket sendMsg(String text, WebSocketListener webSocketListener) {String wsUrl = xfLlmConfig.getWsUrl();Request request = new Request.Builder().url(wsUrl).build();OkHttpClient client = new OkHttpClient.Builder().build();String body = buildBody(text);log.info("llm request body: {}", body);WebSocket webSocket = client.newWebSocket(request, webSocketListener);webSocket.send(body);return webSocket;}@SneakyThrows@Overridepublic String getResult(XFWebSocketListener webSocketListener) {synchronized (webSocketListener.getLock()) {Long maxResponseTime = xfLlmConfig.getMaxResponseTime();long start = System.currentTimeMillis();if (!webSocketListener.isWsCloseFlag()) {log.info("Thread ID: {}, wsCloseFlag:{}, 线程等待", Thread.currentThread().getId(), webSocketListener.isWsCloseFlag());webSocketListener.getLock().wait(maxResponseTime);}long end = System.currentTimeMillis();log.info("Thread ID: {}, wsCloseFlag:{}, 等待时长:{} 线程被唤醒", Thread.currentThread().getId(), webSocketListener.isWsCloseFlag(), (end - start));if ((end - start) > maxResponseTime) {throw new RuntimeException("响应超时,请联系相关人员");}return webSocketListener.getAnswer();}}private String buildBody(String content) {XFLlmRequest request = new XFLlmRequest();XFLlmRequest.Header header = XFLlmRequest.Header.builder().appId(xfLlmConfig.getAppId()).build();request.setHeader(header);XFLlmRequest.Chat chat = XFLlmRequest.Chat.builder().domain(xfLlmConfig.getDomain()).build();XFLlmRequest.Parameter parameter = XFLlmRequest.Parameter.builder().chat(chat).build();request.setParameter(parameter);XFLlmRequest.Text text = XFLlmRequest.Text.builder().content(content).role(xfLlmConfig.getRole()).build();XFLlmRequest.Message message = XFLlmRequest.Message.builder().text(Collections.singletonList(text)).build();XFLlmRequest.Payload payload = XFLlmRequest.Payload.builder().message(message).build();request.setPayload(payload);return JSON.toJSONString(request);}
}

5. 编写controller

用户发起请求的request封装

@Data
public class GenerateSqlRequest {/*** 端口号*/private String port;/*** 主机*/private String host;/*** 密码*/private String password;/*** 用户名*/private String userName;/*** 数据库名字*/private String databaseName;/*** 表的名字*/private String tableName;/*** 用户的问题*/private String problem;
}
@RequestMapping("generate-sql")
@RestController
@RequiredArgsConstructor
public class GenerateSqlController {private final static String URL = "jdbc:mysql://%s:%s/%s";private final XFLlmConfig xfLlmConfig;private final LlmService llmService;@SneakyThrows@PostMappingpublic R generateSql(@RequestBody GenerateSqlRequest request) {String url = getUrl(request);String userName = request.getUserName();String password = request.getPassword();Class.forName("com.mysql.cj.jdbc.Driver");try (Connection conn = DriverManager.getConnection(url, userName, password)) {String tableName = request.getTableName();String query = "SHOW CREATE TABLE " + tableName;try (Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(query)) {if (rs.next()) {String ddl = rs.getString(2);String prompt = getPrompt(ddl, request);XFWebSocketListener webSocketListener = new XFWebSocketListener();llmService.sendMsg(prompt, webSocketListener);String result = llmService.getResult(webSocketListener);return R.success(result);}}} catch (SQLException e) {e.printStackTrace();}return R.fail();}public String getUrl(GenerateSqlRequest request) {return String.format(URL, request.getHost(), request.getPort(), request.getDatabaseName());}public String getPrompt(String ddl, GenerateSqlRequest request) {return String.format(xfLlmConfig.getPrompt(), ddl, request.getProblem());}

6. 运行测试

image-20240225174110107


六、总结

按照这样的一套流程,我们就把LLM接入到系统中,将我们的一个系统实现了智能化,让我们的系统有了自主思考的能力,这是一个不错的Demo。

对此,大家可以根据这种思想,将自己的项目改造,不再是简单的CRUD功能,这也是不错的亮点。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/266092.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode每日一刷】哈希表|纲领、242.有效的字母异位词、349. 两个数组的交集

纲领 &#x1f517;代码随想录理论部分 关于哈希表这个数据结构就不再重复讲了&#xff0c;下面对几个关键点记录一下&#xff1a; 哈希碰撞 解决方法1&#xff1a;拉链法 解决方法2&#xff1a;线性探测法 下面针对做题要用到的三种结构讲一下&#xff08;也是重复造轮子了…

NebulaGraph入门

感谢阅读 官方文档链接NebulaGraph简介nGQLnGQL简介占位标识符和占位符值注释实列大小写区分关键字 基本概念以及相关代码实现补充说明图空间语法以及列子创建克隆官方示例代码(创建并克隆)USE语句指定图空间时查看所有SPACESPACE详情CLEAR SPACE删库跑路&#xff08;看玩笑的说…

fastAdmin表格列表的功能

更多文章&#xff0c;请关注&#xff1a;fastAdmin后台功能详解 | 夜空中最亮的星 FastAdmin是一款基于ThinkPHP5Bootstrap的极速后台开发框架。优点见开发文档 介绍 - FastAdmin框架文档 - FastAdmin开发文档 在这里上传几张优秀的快速入门图: 一张图解析FastAdmin中的表格列…

idea集成git详解教程(实用篇)

0.Git常用命令 Git常用命令-CSDN博客 1.下载git Git - Downloads 一路傻瓜式安装即可&#xff08;NEXT&#xff09; 2.软件测试 在Windows桌面空白处&#xff0c;点击鼠标右键&#xff0c;弹出右键菜单 Git软件安装后&#xff0c;会在右键菜单中增加两个菜单 Git GUI He…

Android Studio level过滤查看各个等级的日志

Android Studio level过滤查看各个等级的日志 旧版as可以在下方的日志输出框选择debug、info&#xff0c;warn、error日志&#xff0c;新版的需要通过在过滤框手动/联想输入 level:xxx&#xff0c;过滤相应等级的日志&#xff0c;如图&#xff1a; android studio/idea返回/前进…

【C语言基础】:深入理解指针(一)

文章目录 一、内存和地址1. 内存2. 如何理解编址 二、指针变量和地址2.1 取地址操作符(&)2.2 指针变量和解引用操作符(*)2.2.1 指针变量2.2.2 如何拆解指针变量2.2.3 解引用操作符 2.3 指针变量的大小 三、指针变量类型的意义3.1 指针的解引用3.2 指针 - 整数3.3 void*指针…

Linux第67步_linux字符设备驱动_注册和注销

1、字符设备注册与注销的函数原型” /*字符设备注册的函数原型*/ static inline int register_chrdev(unsigned int major,\ const char *name, \ const struct file_operations *fops) /* major:主设备号&#xff0c;Limnux下每个设备都有一个设备号&#xff0c;设备号分…

HTTP详解(HTTP的特点,状态码,工作原理,GET和POST的区别,如何解决无状态通信)!!!

文章目录 一、HTTP协议简介二、HTTP的主要特点三、HTTP之URL四、Request和Respons五、HTTP的状态码六、HTTP工作原理七、GET和POST请求的区别八、解决HTTP无状态通信——Cookie和Session 一、HTTP协议简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&…

基础!!!吴恩达deeplearning.ai:卷积层

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 回顾——密集层 Dense Layer卷积层 Convolutional Neural Network定义优势具体说明心电图卷积层搭建 到目前为止&#xff0c;你使用的所有神经网络层都是密集层类型&#xff0c;这…

软件测试有哪些常用的测试方法?

软件测试是软件开发过程中重要组成部分&#xff0c;是用来确认一个程序的质量或者性能是否符合开发之前提出的一些要求。软件测试的目的有两方面&#xff0c;一方面是确认软件的质量&#xff0c;另一方面是提供信息&#xff0c;例如&#xff0c;给开发人员或者程序经理反馈意见…

基于vue-office实现docx、xlsx、pdf文件的在线预览

概述 在做项目的时候会遇到docx、xlsx、pdf等文件的在线预览需求&#xff0c;实现此需求可以有多种解决方式&#xff0c;本文基于vue-office实现纯前端的文件预览。 效果 如下图&#xff0c;分别为docx、xlsx、pdf三种类型的文件在线加载后的效果。你也可以访问官方预览网址…

当Web3叙事寒冬到来,游戏是否是冬日里的“一把火”?

出品&#xff5c;欧科云链研究院 作者&#xff5c;Jason Jiang 以太坊创始人Vitalik在2019年曾说&#xff1a;金融与游戏会是区块链最先落地的场景。 在DeFi金融创新驱动上个周期后&#xff0c;沉寂近两年的Web3游戏板块&#xff0c;如今似乎也在复苏。无论是频繁获得融资&a…

pandas/geopandas 笔记:逐record的轨迹dataFrame转成逐traj_id的轨迹dataFrame

我们现在有这样的一个dataframe&#xff0c;名字为dart 我们需要这样一个DataFrame&#xff0c;每一行有两列&#xff0c;一列是new_installation_id&#xff0c;表示这个轨迹的id&#xff1b;另一列就是这个new_installation_id的轨迹 dart_new dart[[new_installation_id]]…

如何使用Docker部署IT-Tools并结合内网穿透实现公网访问本地工具箱服务

作为程序员&#xff0c;在日常工作中&#xff0c;需要借助一些工具来提高我们工作效率&#xff0c;IT-Tools是为开发人员度身打造的一套便捷在线工具。它提供全面功能&#xff0c;使开发者能以更高效方式完成任务。经由IT-Tools&#xff0c;开发人员能轻松应对各类技术挑战&…

基于java SSM springboot动物检疫信息管理系统设计和实现

基于java SSM springboot动物检疫信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末…

代码遗产:探索祖传代码的历史、挑战与现代融合艺术

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

NC65 rest接口 开发 NC65接口开发

一、在对应模块META-INF下编写 xxx.rest 文件,也要放在Home里对应的目录下。 二、开发接口&#xff0c;继承extends AbstractUAPRestResource&#xff0c;&#xff08;有的项目会继承别的方法如&#xff1a;AbstractNCCRestResource&#xff0c;MTFRestResource&#xff1b;有…

adb下载安装及使用教程

adb下载安装及使用教程 一、ADB的介绍1.ADB是什么&#xff1f;2.内容简介3.ADB常用命令1. ADB查看设备2. ADB安装软件3. ADB卸载软件4. ADB登录设备shell5. ADB从电脑上发送文件到设备6. ADB从设备上下载文件到电脑7. ADB显示帮助信息 4.为什么要用ADB 二、ADB的下载1.Windows版…

Vue <component/> 特殊的内置组件使用

在 Vue 中&#xff0c; 是一个特殊的内置组件&#xff0c;它可以根据提供的数据动态地渲染不同的子组件。这个功能非常有用&#xff0c;因为它可以让你在不同的情况下动态地切换和渲染不同的组件。 将is的值绑定为一个变量&#xff0c;is就变成了v-bind:is“变量名”&#xff…

SpringBoot 3 新特性

目录 1. GraalVM1.1 生成本地可执行应用1.2 生成docker镜像 2. 支持虚拟线程2.1 不开启虚拟线程时压测2.2 开启虚拟线程时压测 3. HTTP Interface 1. GraalVM 使用GraalVM将SpringBoot应用程序编译成本地可执行的镜像文件&#xff0c;可以显著提升启动速度、峰值性能以及减少内…