68 Netty

68 Netty

参考资料

  1. 【硬核】肝了一月的Netty知识点

概念

Netty 是一个高性能、异步事件驱动的网络应用框架,简化了 Java 网络编程,适用于构建高效、可扩展的网络服务器和客户端。

Netty 是基于 Java NIO 的异步事件驱动的网络应用框架,使用 Netty 可以快速开发网络应用,Netty 提供了高层次的抽象来简化 TCP 和 UDP 服务器的编程,但是你仍然可以使用底层的 API。

Netty是一个非阻塞的IO客户端服务器框架

阻塞(Block)与非阻塞(Non-Block)

  • 阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候。

  • 阻塞:往往需要等待缓冲区中的数据准备好过后才处理其他的事情,否则一直等待在那里。

  • 非阻塞:当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回。

在这里插入图片描述

  • Feign 是一个用于调用 RESTful API 的同步框架,调用方会被阻塞,直到接收到响应。在消息队列的场景中,生产者通常需要非阻塞地发送消息,以提高性能和吞吐量。

Netty 核心组件

Channel

Channel是 Java NIO 的一个基本构造。可以看作是传入或传出数据的载体。因此,它可以被打开或关闭,连接或者断开连接。

EventLoop 与 EventLoopGroup

EventLoop 定义了Netty的核心抽象,用来处理连接的生命周期中所发生的事件,在内部,将会为每个Channel分配一个EventLoop

EventLoopGroup 是一个 EventLoop 池,包含很多的 EventLoop。

Netty 为每个 Channel 分配了一个 EventLoop,用于处理用户连接请求、对用户请求的处理等所有事件。EventLoop 本身只是一个线程驱动,在其生命周期内只会绑定一个线程,让该线程处理一个 Channel 的所有 IO 事件。

一个 Channel 一旦与一个 EventLoop 相绑定,那么在 Channel 的整个生命周期内是不能改变的。一个 EventLoop 可以与多个 Channel 绑定。即 Channel 与 EventLoop 的关系是 n:1,而 EventLoop 与线程的关系是 1:1。

ServerBootstrap 与 Bootstrap

Bootstarp 和 ServerBootstrap 被称为引导类,指对应用程序进行配置,并使他运行起来的过程。Netty处理引导的方式是使你的应用程序和网络层相隔离。

Bootstrap 是客户端的引导类,Bootstrap 在调用 bind()(连接UDP)和 connect()(连接TCP)方法时,会新创建一个 Channel,仅创建一个单独的、没有父 Channel 的 Channel 来实现所有的网络交换。

ServerBootstrap 是服务端的引导类,ServerBootstarp 在调用 bind() 方法时会创建一个 ServerChannel 来接受来自客户端的连接,并且该 ServerChannel 管理了多个子 Channel 用于同客户端之间的通信。

ChannelHandler 与 ChannelPipeline

ChannelHandler 是对 Channel 中数据的处理器,这些处理器可以是系统本身定义好的编解码器,也可以是用户自定义的。这些处理器会被统一添加到一个 ChannelPipeline 的对象中,然后按照添加的顺序对 Channel 中的数据进行依次处理。

ChannelFuture

Netty 中所有的 I/O 操作都是异步的,即操作不会立即得到返回结果,所以 Netty 中定义了一个 ChannelFuture 对象作为这个异步操作的“代言人”,表示异步操作本身。如果想获取到该异步操作的返回值,可以通过该异步操作对象的addListener() 方法为该异步操作添加监 NIO 网络编程框架 Netty 听器,为其注册回调:当结果出来后马上调用执行。

Netty 的异步编程模型都是建立在 Future 与回调概念之上的。

心跳

因为 Netty 建立的是长连接,也就是说只要不在 Client 的代码中手动 channel.close(); 那该连接就会一直保持着,直到客户端或者服务器一方关闭。

也不是说长连接它就不好,但大家想想,每一个客户端都一直占着一个连接,即使它后面已经用不到服务器了,而服务器能承受的连接数是有限的,后面再来了真正有需求的用户,它也进不来了,而且长时间的高并发也可能导致服务器宕机。

所以,有没有一种办法,如果我一段时间用不到服务器,就把这个连接给关掉?答:心跳机制。所谓心跳,即在 TCP 长连接中,客户端和服务器之间定期发送的一种特殊的数据包(比如消息内容是某种要求格式、内容),通知对方自己还在线,以确保 TCP 连接的有效性。

在 Netty 中,实现心跳机制的关键是 IdleStateHandler(空闲状态处理器),它的作用跟名字一样,是用来监测连接的空闲情况。然后我们就可以根据心跳情况,来实现具体的处理逻辑,比如说断开连接、重新连接等等。

总结

Netty 是一个高性能的异步事件驱动的网络应用框架,广泛用于开发网络应用程序,如协议服务器和客户端。简单来说这个框架是基于异步事件驱动的网络应用框架,这里最重要的一个点是事件驱动。

何为事件驱动呢?事件驱动就是指它的服务逻辑都是针对发生的事件来触发的,一旦某个事件发生了,就会触发该时间的处理逻辑。比如建立连接、数据读取、数据写入等等情况。

该应用框架总体来说就是为了两个服务直接进行通信,只不过这个是异步通信,而不是像之前那样的同步通信,它是非阻塞的,具有很高的性能。那么连接两个节点之间进行通信的称为通道Channel),通过这个通道来实现双方之间的通信。这些都是应用层面的,对于传输层来说,具体使用的是TCP协议还是UDP协议都做了适配。

ChannelHandler 是处理特定事件和数据的组件。你可以定义自己的 ChannelHandler,重写方法来处理数据的编解码、连接的生命周期事件、异常处理等。这个可以看成通道上的管理人员,我们可以在通道的两头编写的自定义的入站和出站逻辑。

在网络通信中,数据通常需要进行编码和解码。在 Netty 中,编解码的过程通过 ChannelHandler 的实现来完成。Netty 提供了 MessageToByteEncoderByteToMessageDecoder 等抽象类,简化了这一过程。

ChannelPipeline 是一个关键概念,它允许开发者将多个 ChannelHandler 组合在一起,形成一个处理链。当数据在 Channel 中流动时,它会依次经过链中的每个处理器。这种设计使得数据的处理过程可以灵活配置,支持不同的协议和业务逻辑。

例如:

public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline()//空闲检测.addLast(new ServerIdleStateHandler()).addLast(new ProtobufVarint32FrameDecoder()).addLast(new ProtobufDecoder(MessageBase.Message.getDefaultInstance())).addLast(new ProtobufVarint32LengthFieldPrepender()).addLast(new ProtobufEncoder()).addLast(new NettyServerHandler());}
}

这里就是一个ChannelPipeline。

Reactor模型是Netty采用的线程模型,下面是其一个图:

在这里插入图片描述

Netty 的线程模型基于 Reactor 模式,这种模式特别适合于处理大量的并发连接。Reactor 模式的基本思路是将 I/O 操作与业务逻辑处理分离,将 I/O 事件的处理和业务逻辑处理分配给不同的线程

事件循环: 每个 EventLoop 会不断地循环处理事件,包括连接事件、读事件和写事件。EventLoop 负责从操作系统获取可读或可写的 Channel,并将这些事件分发给对应的 ChannelHandler 进行处理。

Netty的处理架构如下:

在这里插入图片描述

Netty主要在Reactor的主从模型上进行了一些改进后得到了目前Netty使用的Reactor模型。

在这里插入图片描述

Netty工作原理

参考资料:【Netty系列】Netty高性能架构设计以及光速入门

一图见真知

在这里插入图片描述

Netty 抽象出了两组线程池BossGroup和WorkerGroup,其中BossGroup专门负责接受客户端的连接WorkerGroup专门负责网络的读写。BossGroup和WorkerGroup的类型都是NioEventLoopGroup。NioEventLoopGroup相当于一个事件循环组,这个组种含有多个事件循环,每一个事件循环是一个NioEventLoop。NioEeventLoop表示一个不断循环执行处理任务的线程,可以有多个线程,也就是说可以含有多个NioEventLoop,每个NioEventLoop都有一个Selector,用于监听绑定在其上的socket的网络通讯。

EventLoop 和 EventLoopGroupEventLoop 是 Netty 的事件循环,它处理 Channel 上的所有事件,包括 I/O 事件、任务调度等。每个 EventLoop 负责处理一个或多个 Channel,确保同一个 Channel 的所有 I/O 操作都在同一个线程中执行,避免线程安全问题。EventLoopGroupEventLoop 的集合,通常分为两类:

  • BossGroup:负责处理新的连接请求。
  • WorkerGroup:负责处理已经建立的连接的 I/O 操作。

Bootstrap/ServerBootstrap:用于启动 Netty 应用程序的辅助类。Bootstrap 用于客户端,ServerBootstrap 用于服务器。它们简化了配置和初始化过程。

SpringBoot集成Netty

参考资料

  • Springboot 2.0 +protobuf + Netty 实战(附源码)
  • Spring Boot与Netty的完美结合:打造高性能网络通信

protobuf协议格式

在整合使用 Netty 的过程中,我们使用 Google 的protobuf定义消息格式,下面来简单介绍下 protobuf。

了解一个新的事物,我们从这几个方面快速的了解:

  • 它是什么?Protobuf是一个数据格式,专业术语为:一种结构化数据存储格式;
  • 它有什么用?通常用于结构化数据的序列化和反序列化;
  • 它相比较之前存在的有什么优点?解决了什么问题?它相对于JSON来说,性能更好,支持跨语言(因为它最后是二进制格式的数据编码)

通过上面三个问题就可以对Protobuf有一个初步清晰的了解。

引入Netty依赖

        <!-- https://mvnrepository.com/artifact/io.netty/netty-all --><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.112.Final</version></dependency>

Netty服务端

@Component
@Slf4j
public class NettyServer {/*** boss 线程组用于处理连接工作*/private final EventLoopGroup boss = new NioEventLoopGroup();/**在* work 线程组用于数据处理*/private final EventLoopGroup work = new NioEventLoopGroup();//    @Value("${netty.port}")private static final Integer port = 54021;// @PostConstruct 是一个用于 Java EE 和 Spring 框架中的注解,标记在一个方法上,表示这个方法将在依赖注入完成后被自动调用。// 它通常用于进行初始化操作,例如设置默认值、执行启动时的逻辑、或者进行资源的准备。/**** @Description 启动Netty Server* @return {@link  }* @Author yaoHui* @Date 2024/10/10*/@PostConstructpublic void start() throws InterruptedException {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(boss,work)// 指定Channel.channel(NioServerSocketChannel.class)//使用指定的端口设置套接字地址.localAddress(new InetSocketAddress(port))// 方法设置了 Socket 选项 SO_BACKLOG,它指定了在连接队列中可以排队的最大连接数。当服务器正在处理现有连接时,// 新的连接请求会被放入队列中,直到当前连接处理完成。1024 是队列的长度,这个值可以根据需要进行调整。.option(ChannelOption.SO_BACKLOG,1024)// 设置 SO_KEEPALIVE 选项为 true,这意味着在 TCP 连接上启用 TCP 保活机制。// 如果连接闲置时间过长,系统会发送保活探测包,以保持连接的活跃状态。.childOption(ChannelOption.SO_KEEPALIVE,true)// 设置 TCP_NODELAY 选项为 true,启用 Nagle 算法。// 这会在发送小数据包时禁用延迟,从而减少数据包的发送延迟,提高实时性。.childOption(ChannelOption.TCP_NODELAY,true).childHandler(new NettyServerHandlerInitializer());ChannelFuture future = serverBootstrap.bind().sync();if (future.isSuccess()){log.info("Netty Server Running");}}@PreDestroypublic void destroy() throws InterruptedException {boss.shutdownGracefully().sync();work.shutdownGracefully().sync();log.info("Netty Server Stop");}
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof MessageBase.Message) {// 将接收到的消息转换为 Protobuf 消息MessageBase.Message message = (MessageBase.Message) msg;// 处理消息(例如,打印消息内容)log.info("Received message:");log.info(message.toString());// 可选:根据接收到的消息发送响应MessageBase.Message response = MessageBase.Message.newBuilder().setRequestId(message.getRequestId()).setCmd(MessageBase.Message.CommandType.ACK).build();ctx.writeAndFlush(response); // 发送响应} else {// 如果接收到的消息不是预期的类型,可以选择忽略或者抛出异常System.err.println("Received an unknown message type: " + msg.getClass().getName());ctx.fireChannelRead(msg); // 继续向下传递}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {// 处理异常cause.printStackTrace();ctx.close(); // 关闭连接}
}
public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline()//空闲检测.addLast(new ServerIdleStateHandler()).addLast(new ProtobufVarint32FrameDecoder()).addLast(new ProtobufDecoder(MessageBase.Message.getDefaultInstance())).addLast(new ProtobufVarint32LengthFieldPrepender()).addLast(new ProtobufEncoder()).addLast(new NettyServerHandler());}
}
@Slf4j
public class ServerIdleStateHandler extends IdleStateHandler {Integer times = 0;/*** 设置空闲检测时间为 30s*/private static final int READER_IDLE_TIME = 60;public ServerIdleStateHandler() {super(READER_IDLE_TIME, READER_IDLE_TIME, READER_IDLE_TIME, TimeUnit.SECONDS);}@Overrideprotected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {log.info("{} 秒内没有读取到数据,关闭连接", READER_IDLE_TIME);System.out.println(ctx.channel().remoteAddress() + "发生超时事件--" + evt);ctx.channel().close();}
}

Netty客户端

@Component
@Slf4j
public class NettyClient {private static final EventLoopGroup group = new NioEventLoopGroup();private static final Integer port = 54021;private static final String host = "localhost";private static SocketChannel socketChannel;/**** @Description Netty客户端启动函数 调用Start可以启动对Netty服务端的连接* @return {@link }* @Author yaoHui* @Date 2024/10/11*/@PostConstructprivate void start(){Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).remoteAddress(host, port).option(ChannelOption.SO_KEEPALIVE, true).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline()// 空闲检测.addLast(new IdleStateHandler(60, 60, 60)) // 60秒写空闲,30秒读空闲.addLast(new HeartbeatHandler()).addLast(new ProtobufVarint32FrameDecoder()).addLast(new ProtobufDecoder(MessageBase.Message.getDefaultInstance())).addLast(new ProtobufVarint32LengthFieldPrepender()).addLast(new ProtobufEncoder()).addLast(new NettyClientHandler()); // 自定义处理器}});ChannelFuture future = bootstrap.connect();//客户端断线重连逻辑future.addListener((ChannelFutureListener) future1 -> {if (future1.isSuccess()) {log.info("连接Netty服务端成功");} else {log.info("连接失败,进行断线重连");future1.channel().eventLoop().schedule(this::start, 10, TimeUnit.SECONDS);}});socketChannel = (SocketChannel) future.channel();sendMessageThread.setSocketChannel(socketChannel);}}

proto文件

//protobuf语法有 proto2和proto3两种,这里指定 proto3
syntax = "proto3";
// 文件选项
option java_package = "com.fang.screw.client.protocol";
option java_outer_classname = "MessageBase";
// 消息模型定义
message Message {string requestId = 1;CommandType cmd = 2;string content = 3;int32 retryCount = 4;string urlPath = 5;enum CommandType {NORMAL = 0; //常规业务消息HEARTBEAT_REQUEST = 1; //客户端心跳消息HEARTBEAT_RESPONSE = 2; //服务端心跳消息ACK = 3;}
}

需要把Protobuf文件进行编译,具体如何操作请查阅相关资料。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Premiere半色调动漫风格视频叠加特效素材MOGRT

Premiere Pro 半色调叠加素材视频模板&#xff0c;使用这个半色调效果轻松设置视频或图像的样式。可以使用自定义选项&#xff0c;让工作流程更加高效。 特征&#xff1a; 15个半色调叠加效果。 Adobe Premiere Pro 2023 4K分辨率&#xff08;38402160&#xff09;。 包括视频…

回溯法与迭代法详解:如何从手机数字键盘生成字母组合

在这篇文章中&#xff0c;我们将详细介绍如何基于手机数字键盘的映射&#xff0c;给定一个仅包含数字 2-9 的字符串&#xff0c;输出它能够表示的所有字母组合。这是一个经典的回溯算法问题&#xff0c;适合初学者理解和掌握。 问题描述 给定一个数字字符串&#xff0c;比如 …

TikTok流量不好是为什么?是网络没选对吗?

很多人发现他们的TikTok视频观看量不高&#xff0c;点赞和分享率也低&#xff0c;就会开始怀疑是不是网络选择不当导致了这一问题。虽然网络确实是导致流量不佳的一大原因之一&#xff0c;但也不能忽视其他因素&#xff0c;包括内容质量、时机选择、互动参与等方面。本文将揭示…

桌面运维转网络要做什么准备,高级网工学习路线分享_运维转网络工程师好转岗吗

如果你的船不进来&#xff0c;请游过去。 做过桌面运维的朋友都知道&#xff0c;这个岗位相当于做牛做马。我做桌面运维的时候要修监控门禁&#xff0c;消防报警广播音响&#xff0c;还要懂暖通空调下水管道疏通&#xff0c;电梯保养与维护&#xff0c;我听到有些同行还得会修桌…

数据采集崩溃恢复:保障业务稳定运行的关键技术特性

一、场景描述 在当今信息时代&#xff0c;数据已成为企业核心竞争力的重要组成部分。对于许多企业而言&#xff0c;数据的采集、处理和分析至关重要。然而&#xff0c;在数据采集和处理过程中&#xff0c;系统崩溃或故障是无法避免的现象。如何在数据采集过程中确保数据的完整…

计量校准公司对校准工程师,会有什么资质要求?

计量校准是指利用一些计量校准工具&#xff0c;对机器、仪器等进行测量和校准。来实现基本功能的正常使用。计量校准安排&#xff0c;是指根据委托方的要求&#xff0c;按照计量器具校准标准&#xff0c;向社会提供计量器具校准服务的安排。今天&#xff0c;我们就来看看计量校…

腾讯音乐:从 Elasticsearch 到 Apache Doris 内容库升级,统一搜索分析引擎,成本直降 80%

导读&#xff1a; 为满足更严苛数据分析的需求&#xff0c;腾讯音乐借助 Apache Doris 替代了 Elasticsearch 集群&#xff0c;统一了内容库数据平台的内容搜索和分析引擎。并基于 Doris 倒排索引和全文检索的能力&#xff0c;支持了复杂的自定义标签计算&#xff0c;实现秒级查…

24最新新手入门指南:Stable Diffusion!

前言 Stable Diffusion&#xff0c;一款新兴的开源AI绘画软件&#xff0c;正逐渐成为数字艺术家和爱好者的新宠。它的强大功能让用户能够轻松创造出令人印象深刻的数字艺术作品。 无论你是专业艺术家还是艺术新手&#xff0c;Stable Diffusion都为你提供了一个探索创造力的新…

如何卸载电脑上的软件?电脑软件彻底删除的3个常见方法(强力卸载注册表)

电脑使用久了&#xff0c;难免会遇到卡顿&#xff0c;运行不流畅的情况&#xff0c;这属于正常现象。造成电脑卡顿的很大部分原因就是因为电脑安装了太多软件了&#xff0c;特别是一些“来路不明”的软件容易影响电脑运行速度。使用电脑时&#xff0c;定期清理电脑垃圾&#xf…

这本书有亿点厉害!带你快速入门扩散模型,从原理到实战!!-《扩散模型从原理到实战》

AIGC爱好者有福了&#xff0c;快看看这本《扩散模型》 书名&#xff1a;《扩散模型&#xff1a;从原理到实战》 作者&#xff1a; 李忻玮等 适合人群&#xff1a; 对扩散模型感兴趣的AI研究人员&#xff1b;有使用AIGC生成图片需求的从业人员&#xff1b;对stable Diffusi…

小米13工程固件预览 修复底层分区 修复nv损坏主板电阻 默认开启diag端口

机型名称 :小米 13【用于以下型号的小米机型:2211133G, 2211133C】机型代号 :fuxi 小米13搭载高通骁龙 8 Gen2八核处理器,预装miui14操作系统;后置5000万像素主镜头+1200万像素超广角镜头+1000万像素长焦镜头,前置3200万像素摄像头;搭载4500毫安时容量不可拆卸电池…

邮件营销案例成功技巧:如何打动目标客户?

邮件营销案例分析成功策略&#xff1f;有哪些优质邮件营销案例&#xff1f; 企业不仅能够与目标客户建立联系&#xff0c;还能有效地推动销售和提升品牌忠诚度。MailBing将通过多个邮件营销成功案例&#xff0c;探讨如何打动目标客户&#xff0c;并分享一些实用的技巧。 邮件…

Rad Studio 12.2 出来了

RAD Studio 12.1之后5个月&#xff0c;RAD Studio 12之后10个月&#xff0c;新发布的RAD Studio12.2加入了客户的反馈&#xff0c;利用人工智能能力的编码支持&#xff0c;64-bit版本的编译器等先进的功能&#xff0c;为应用开发提供更强有力的支持。 本文介绍了RAD Studio 12…

JS 运算符

目录 1. 赋值运算符 2. 一元运算符 2.1 自增 2.1.1 前置自增 2.1.2 后置自增 2.1.3 前置与后置自增对比 3. 比较运算符 3.1 字符串比较 4. 逻辑运算符 4.1 案例 5. 运算符优先级 1. 赋值运算符 2. 一元运算符 2.1 自增 2.1.1 前置自增 2.1.2 后置自增 2.1.3 前置与后…

圈子系统APP小程序H5该如何设置IM?

搭建圈子系统的常见问题,以及圈子论坛系统的功能特点 社交圈子论坛系统的概念 圈子小程序源码 多客圈子系统 圈子是什么软件 跟进圈一个系统的软件 为圈子系统APP小程序H5设置IM&#xff08;即时通讯&#xff09;&#xff0c;需要遵循一系列步骤来确保通讯功能的稳定、安全和高…

magic-html : 通用HTML数据提取器!DocAI:从非结构化文档中提取结构化数据!强大、快速、开源的微信机器人底层框架:wcf.js!

magic-html : 通用HTML数据提取器&#xff01;DocAI&#xff1a;从非结构化文档中提取结构化数据&#xff01;强大、快速、开源的微信机器人底层框架&#xff1a;wcf.js&#xff01; magic-html : 通用HTML数据提取器 magic-html提供了一套工具&#xff0c;能够轻松地从HTML中…

水凝胶制造新突破,DIW 技术来助力,打印参数很关键

大家好&#xff01;今天我们来了解一篇《Innovations in hydrogel-based manufacturing: A comprehensive review of direct ink writing technique for biomedical applications》发表于《Advances in Colloid and Interface Science》。水凝胶因其独特性质在多领域备受关注&a…

STL之set、map的使用

STL之set、map 1. 序列式容器和关联式容器2. set系列的使⽤参考文档链接&#xff1a;2.1 set的介绍&#xff08;2&#xff09;set的增删查2.2 multiset的介绍 3 map3.1 参考文档3.2 map类的介绍3.3 pair类型介绍3.4 map的构造3.6 map的数据修改3.7 multimap和map的差异 1. 序列…

解锁未来新技能——揭秘人工智能工程师证书!

为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国务院印发《关于“十四五”数字经济发展规划》等有关工作的部署要求&#xff0c;深入实施人才强国战略和创新驱动发展战略&#xff0c;加强全国数字化人才队伍建设&#xff0c;持续推进人工智能从业人员…

MySQL 【日期】函数大全(二)

DATE_ADDDATE_FORMATDATE_SUBDATEDIFFDAYDAYNAMEDAYOFMONTHDAYOFWEEK 1、DATE_ADD DATE_ADD(date, value) &#xff1a;在指定的日期/时间上加上指定的时间间隔加并返回新的日期/时间。 DATE_ADD(date, value) DATE_ADD(date, INTERVAL value unit) date&#xff1a;需要操作…