GolangWebSocket开发 gorilla/websocket实践

Golang通过gorilla/websocket库结合Goroutine和Channel实现高效并发连接管理,利用ClientManager集中处理注册、注销与广播,配合sync.RWMutex保障map操作安全;通过http.Server.Shutdown实现服务器优雅关闭,监听中断信号并清理连接;为维护连接活性,采用Ping/Pong心跳机制,设置读取超时并注册PongHandler更新客户端活跃状态,及时发现并清理失效连接,确保系统稳定可靠。

golangwebsocket开发 gorilla/websocket实践

WebSocket开发在现代实时应用中扮演着核心角色,而

gorilla/websocket

库在Golang生态中,无疑是实现这一目标的强力且成熟的选择。在我看来,它提供了一个非常平衡的API,既不会让你陷于底层细节的泥沼,又能给予你足够的控制力去构建健壮、高效的实时通信服务。它的设计哲学与Go语言的并发模型契合得很好,使得开发过程直观且富有乐趣。

package mainimport (    "log"    "net/http"    "time"    "sync" // 用于管理客户端连接的并发安全    "context" // 用于优雅关闭    "os"    "os/signal"    "github.com/gorilla/websocket")// 定义一个Upgrader,用于将HTTP连接升级为WebSocket连接var upgrader = websocket.Upgrader{    ReadBufferSize:  1024,    WriteBufferSize: 1024,    CheckOrigin: func(r *http.Request) bool {        // 允许所有源,实际项目中应根据需求进行严格校验        return true    },}// ClientManager 结构体,用于管理所有活跃的WebSocket客户端type ClientManager struct {    clients    map[*websocket.Conn]bool    broadcast  chan []byte    register   chan *websocket.Conn    unregister chan *websocket.Conn    mu         sync.RWMutex}// NewClientManager 创建并返回一个新的ClientManager实例func NewClientManager() *ClientManager {    return &ClientManager{        clients:    make(map[*websocket.Conn]bool),        broadcast:  make(chan []byte),        register:   make(chan *websocket.Conn),        unregister: make(chan *websocket.Conn),    }}// Start 启动客户端管理器,处理注册、注销和广播消息func (manager *ClientManager) Start() {    for {        select {        case conn := <-manager.register:            manager.mu.Lock()            manager.clients[conn] = true            manager.mu.Unlock()            log.Printf("New client connected: %s", conn.RemoteAddr())        case conn := <-manager.unregister:            manager.mu.Lock()            if _, ok := manager.clients[conn]; ok {                delete(manager.clients, conn)                conn.Close()            }            manager.mu.Unlock()            log.Printf("Client disconnected: %s", conn.RemoteAddr())        case message := <-manager.broadcast:            manager.mu.RLock()            for conn := range manager.clients {                go func(conn *websocket.Conn) {                    // 尝试向客户端发送消息,如果失败则注销该客户端                    if err := conn.WriteMessage(websocket.TextMessage, message); err != nil {                        log.Printf("Error sending message to client %s: %v", conn.RemoteAddr(), err)                        manager.unregister <- conn                    }                }(conn)            }            manager.mu.RUnlock()        }    }}// wsHandler 处理WebSocket连接请求func wsHandler(manager *ClientManager, w http.ResponseWriter, r *http.Request) {    conn, err := upgrader.Upgrade(w, r, nil)    if err != nil {        log.Printf("Failed to upgrade connection: %v", err)        return    }    manager.register <- conn    defer func() {        manager.unregister <- conn    }()    for {        // 设置读取超时,防止客户端无响应导致连接一直占用资源        conn.SetReadDeadline(time.Now().Add(60 * time.Second)) // 60秒无消息则超时        messageType, message, err := conn.ReadMessage()        if err != nil {            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {                log.Printf("Read error: %v", err)            }            break // 连接关闭或出现错误,退出循环        }        log.Printf("Received message from %s: %s", conn.RemoteAddr(), string(message))        // 简单地将收到的消息广播给所有连接的客户端        if messageType == websocket.TextMessage {            manager.broadcast <- message        }    }}func main() {    manager := NewClientManager()    go manager.Start() // 启动客户端管理器协程    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {        wsHandler(manager, w, r)    })    server := &http.Server{Addr: ":8080"}    // 优雅关闭    ctx, cancel := context.WithCancel(context.Background())    defer cancel()    go func() {        sigChan := make(chan os.Signal, 1)        signal.Notify(sigChan, os.Interrupt) // 监听中断信号        <-sigChan // 阻塞直到接收到信号        log.Println("Shutting down server...")        if err := server.Shutdown(ctx); err != nil {            log.Fatalf("Server shutdown failed: %v", err)        }    }()    log.Println("WebSocket server starting on :8080")    if err := server.ListenAndServe(); err != http.ErrServerClosed {        log.Fatalf("Server failed to start: %v", err)    }    log.Println("Server gracefully stopped.")}

Golang WebSocket如何高效管理并发连接与消息流?

在Go语言中,处理高并发的WebSocket连接,其核心优势在于Go的并发原语——Goroutine和Channel。

gorilla/websocket

库与Go的并发模型结合得天衣无缝。

每个客户端连接到WebSocket服务器后,

upgrader.Upgrade

方法成功返回一个

*websocket.Conn

对象。我们通常会为每个新连接启动一个独立的Goroutine来处理其读写操作。这种“一连接一协程”的模式,在Go语言中是非常轻量级的,因为Goroutine的开销远小于传统线程。

消息流的管理则可以通过Channel来实现。在上面的示例中,我创建了一个

ClientManager

,它内部维护了三个Channel:

register

用于新连接的注册,

unregister

用于连接的注销,以及

broadcast

用于广播消息。

立即学习“go语言免费学习笔记(深入)”;

当一个客户端发送消息时,消息会被发送到

broadcast

Channel。

ClientManager

的

Start

方法在一个独立的Goroutine中运行,它会监听这些Channel。当

broadcast

Channel接收到消息时,

ClientManager

会遍历所有已注册的客户端连接,并为每个连接启动一个新的Goroutine来尝试发送消息。

这样做的好处是显而易见的:

解耦读写操作: 每个连接的读操作在一个Goroutine中,写操作(尤其是在广播时)也可以在独立的Goroutine中进行,避免了阻塞。并发安全:

ClientManager

使用

sync.RWMutex

来保护其内部的

clients

map,确保在多个Goroutine同时访问或修改map时不会出现竞态条件。非阻塞通信: Channel的特性使得消息传递是非阻塞的,发送者将消息放入Channel后可以立即返回,接收者则在Channel中等待消息。这对于构建响应迅速的系统至关重要。

当然,这种模式也有其考量点。例如,当连接数量巨大时,维护一个庞大的

clients

map以及频繁的锁操作可能会成为瓶颈。对于超大规模的并发连接,可能需要考虑更高级的架构,比如将客户端管理分散到多个服务实例,或者使用更专业的Pub/Sub系统(如Redis Pub/Sub、Kafka)来分发消息,但对于大多数中等规模的应用,这种基于Goroutine和Channel的模式已经足够强大且易于维护。

如何优雅地关闭Golang WebSocket服务器并处理连接中断?

服务器的优雅关闭和客户端连接的健壮处理,是任何生产级应用都必须面对的问题。在

gorilla/websocket

的实践中,这主要涉及几个方面:

服务器层面的优雅关闭: Go的

net/http

包提供了

http.Server.Shutdown

方法,它允许服务器在接收到中断信号(如

Ctrl+C

)时,停止接受新连接,并等待现有连接处理完毕。结合

os.Signal

和

context

,我们可以实现这一点。在

main

函数中,我监听了

os.Interrupt

信号,当收到信号时,调用

server.Shutdown(ctx)

。

Shutdown

方法会给正在处理的HTTP请求(包括WebSocket升级前的请求)一个完成的机会。对于已建立的WebSocket连接,它不会强制关闭,需要我们自行管理。

客户端连接的断开处理:

正常关闭: 当客户端主动关闭WebSocket连接时,

conn.ReadMessage

会返回一个特定的错误,通常是

websocket.CloseGoingAway

或

websocket.CloseNormalClosure

。

gorilla/websocket

提供了

websocket.IsUnexpectedCloseError

来帮助我们判断是否是预期内的关闭。异常断开: 网络波动、客户端崩溃或服务器端错误都可能导致连接异常断开。此时

conn.ReadMessage

也会返回错误(例如

io.EOF

或网络错误)。超时处理: 长时间没有活动的连接会消耗服务器资源。

gorilla/websocket

允许设置读写超时:

conn.SetReadDeadline

和

conn.SetWriteDeadline

。当在设定的时间内没有读到数据或写出数据时,相应的操作会返回错误,从而触发连接关闭。我在示例中为

ReadMessage

设置了超时,这有助于及时发现并清理“死掉”的连接。注销机制: 无论连接是正常关闭、异常断开还是超时,都应该通过

ClientManager

的

unregister

Channel将该连接从活跃客户端列表中移除,并调用

conn.Close()

释放资源。这是非常关键的一步,避免了资源泄露。

处理这些情况时,关键在于

conn.ReadMessage

的错误处理循环。一旦

ReadMessage

返回错误,就意味着连接不可用,我们应该立即跳出该连接的读循环,并触发注销流程。我个人觉得,对于生产环境,细致的错误日志和监控是不可或缺的,它们能帮助我们快速定位连接异常的根本原因。

Golang WebSocket心跳机制(Ping/Pong)的实现与连接活性维护

WebSocket连接的“活性”维护是一个常被忽视但极其重要的实践。想象一下,一个客户端连接到你的服务器,然后用户长时间不操作,或者网络中间件(如NAT、负载均衡器)有空闲超时设置,连接很可能在不经意间被默默地切断,而两端都不知道。这就是心跳机制发挥作用的地方。

WebSocket协议本身就支持Ping/Pong帧。

gorilla/websocket

库对此提供了非常友好的API:

Ping帧: 服务器可以周期性地向客户端发送Ping帧。客户端接收到Ping帧后,应该自动回复Pong帧。Pong帧: 客户端回复的Pong帧告诉服务器,客户端仍然在线且连接活跃。

实现方式:

服务器发送Ping:我们可以为每个连接启动一个独立的Goroutine,或者在

ClientManager

中设置一个定时器,周期性地向所有活跃连接发送Ping帧。在示例中,为了简化,我没有直接在代码中展示Ping发送逻辑,但通常会像这样:

// 在每个连接的Goroutine中,或者一个独立的定时器Goroutine中go func() {    ticker := time.NewTicker(30 * time.Second) // 每30秒发送一次Ping    defer ticker.Stop()    for range ticker.C {        if err := conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {            log.Printf("Ping failed for %s: %v", conn.RemoteAddr(), err)            manager.unregister <- conn // Ping失败,认为连接已死            return        }    }}()

设置Pong Handler:

gorilla/websocket

允许你通过

conn.SetPongHandler

设置一个回调函数,当接收到Pong帧时会被调用。这个回调函数可以用来更新连接的“最后活跃时间”,从而判断连接是否存活。

// 在wsHandler中,升级连接后lastPongTime := time.Now()conn.SetPongHandler(func(appData string) error {    lastPongTime = time.Now() // 收到Pong,更新活跃时间    log.Printf("Received pong from %s", conn.RemoteAddr())    // 可以根据需要设置读取超时,确保在一定时间内必须收到pong    conn.SetReadDeadline(time.Now().Add(60 * time.Second)) // 比如,收到pong后,设置60秒内必须有下一次读或pong    return nil})

通过结合

SetReadDeadline

和Pong Handler,我们可以构建一个强大的活性检测机制。服务器发送Ping,并期待在一定时间内收到Pong或任何其他消息。如果超时没有收到,就认为连接已死并关闭它。

心跳机制不仅能防止连接被中间件断开,还能帮助我们及时清理“僵尸连接”,释放服务器资源。这对于构建高可用、高并发的实时系统是不可或缺的一环。

以上就是GolangWebSocket开发 gorilla/websocket实践的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1399422.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Golang协程通信方式 channel与共享内存对比
上一篇 2025年12月15日 16:11:34
怎样用Golang实现目录监控 对比fsnotify与inotify系统调用差异
下一篇 2025年12月15日 16:11:42

相关推荐

  • 命令行 AI 编程工具 Codex CLI 已集成全新 GPT-5-Codex 模型

    命令行 AI 编程工具 Codex CLI 已集成全新 GPT-5-Codex 模型命令行 AI 编程工具 Codex CLI 已集成全新 GPT-5-Codex 模型命令行 AI 编程工具 Codex CLI 已集成全新 GPT-5-Codex 模型命令行 AI 编程工具 Codex CLI 已集成全新 GPT-5-Codex 模型

    openai 为其命令行工具 codex cli 推出了全新 0.36.0 版本,重磅集成了先进的 gpt-5-codex 模型,大幅提升了代码生成效率、逻辑推理能力及输出质量。本次更新还新增了通过 agents.md 文件对 ai 行为进行精细化管理的功能。 Codex CLI 是一款轻量级 AI…

    2026年10月2日 • 用户投稿
    200
  • Claude支持哪些平台使用 各平台Claude客户端下载与登录教程

    Claude支持哪些平台使用 各平台Claude客户端下载与登录教程Claude支持哪些平台使用 各平台Claude客户端下载与登录教程Claude支持哪些平台使用 各平台Claude客户端下载与登录教程Claude支持哪些平台使用 各平台Claude客户端下载与登录教程

    本文旨在介绍Claude AI目前支持的使用平台,并提供在这些平台上下载客户端(如适用)或访问并登录的详细步骤。通过阅读本文,用户将能够清晰了解如何在不同环境下便捷地使用Claude服务。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ Cl…

    2026年10月2日 • 用户投稿
    400
  • 编程新霸!微软重磅推出命令行新工具,数小时冲击GitHub榜首

    编程新霸!微软重磅推出命令行新工具,数小时冲击GitHub榜首编程新霸!微软重磅推出命令行新工具,数小时冲击GitHub榜首编程新霸!微软重磅推出命令行新工具,数小时冲击GitHub榜首编程新霸!微软重磅推出命令行新工具,数小时冲击GitHub榜首

    微软推出令人耳目一新的命令行工具,迅速登顶github趋势榜首! 这不再是你记忆中的传统命令行。 许多用户对Windows系统上黑底白字的命令行界面感到厌倦: 然而,在昨天的微软全球开发者大会 Build 2019上,微软推出的Windows Terminal引起了全场的惊叹——命令行界面竟然可以如…

    2026年10月2日 • 用户投稿
    000
  • 使用Java Stream高效处理列表重复对象:按ID去重并保留最新记录

    使用Java Stream高效处理列表重复对象:按ID去重并保留最新记录使用Java Stream高效处理列表重复对象:按ID去重并保留最新记录使用Java Stream高效处理列表重复对象:按ID去重并保留最新记录使用Java Stream高效处理列表重复对象:按ID去重并保留最新记录

    本文详细介绍了如何利用Java Stream API,特别是Collectors.toMap的三参数版本结合BinaryOperator.maxBy,优雅地处理列表中具有重复ID的对象。核心思想是将具有相同ID的对象映射到Map中,并通过自定义合并函数保留具有最新时间戳的记录,最终生成一个去重且保留…

    2026年10月2日 • 用户投稿
    000
  • 如何用ChatGPT写论文 ChatGPT学术写作技巧与提示词模板

    如何用ChatGPT写论文 ChatGPT学术写作技巧与提示词模板如何用ChatGPT写论文 ChatGPT学术写作技巧与提示词模板如何用ChatGPT写论文 ChatGPT学术写作技巧与提示词模板如何用ChatGPT写论文 ChatGPT学术写作技巧与提示词模板

    本文将探讨如何利用ChatGPT进行学术论文写作,并提供实用的技巧与提示词模板。我们将逐步讲解如何运用这一工具,从构思到修改,帮助用户更好地掌握使用ChatGPT提升学术写作效率的方法。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 规划与…

    2026年10月2日 • 用户投稿
    000
  • 阿里通义实验室发布端到端语音识别大模型 FunAudio-ASR

    阿里通义实验室发布端到端语音识别大模型 FunAudio-ASR阿里通义实验室发布端到端语音识别大模型 FunAudio-ASR阿里通义实验室发布端到端语音识别大模型 FunAudio-ASR阿里通义实验室发布端到端语音识别大模型 FunAudio-ASR

    阿里巴巴通义实验室推出了全新的端到端语音识别大模型 funaudio-asr。该模型引入创新的 context 模块,显著提升了在高噪声环境下的识别稳定性,将幻觉率从 78.5% 大幅下降至 10.7%,降幅接近 70%。 FunAudio-ASR 基于数千万小时的真实音频数据训练而成,并深度融合了…

    2026年10月2日 • 用户投稿
    200
  • 共谋业务智胜之道 2025 VDC互联网技术分会引关注

    共谋业务智胜之道 2025 VDC互联网技术分会引关注共谋业务智胜之道 2025 VDC互联网技术分会引关注共谋业务智胜之道 2025 VDC互联网技术分会引关注共谋业务智胜之道 2025 VDC互联网技术分会引关注

    2025年度vivo开发者大会于10月10日顺利召开,延续“同心·同行”的主题,设置了主会场及11个专题分会场。在互联网技术分会中,多位vivo技术专家围绕拨测与融合流量管理、微服务架构优化、全链路多版本环境落地、gpu容器化与ai训练平台建设等方向,分享了最新的技术探索与实践经验,与线上观众共同探…

    2026年10月2日 • 用户投稿
    000
  • Java自定义类方法链式调用与对象状态修改实践

    在Java中,实现自定义类方法链式调用以修改对象属性的关键在于让修改方法返回当前类的实例(this)。通过返回this,不仅可以连续调用同一对象的其他方法,还能将操作后的对象赋值给同类型变量,从而构建出更简洁、流畅的代码风格。 引言:理解Java方法链式调用的需求 在java编程中,我们经常会遇到需…

    2026年10月2日
    200
  • PHP操作MySQL数据库时与Elasticsearch集成的应用

    在php中操作mysql数据库并与elasticsearch集成可以通过以下步骤实现:1. 使用mysqli或pdo扩展连接mysql数据库进行数据操作。2. 利用elasticsearch的php客户端库进行数据索引和搜索。3. 通过定时任务或触发器实现mysql数据的实时同步到elasticse…

    2026年10月2日
    000
  • 多模态AI能识别哪些内容 多模态AI支持的输入类型大全

    多模态AI能识别哪些内容 多模态AI支持的输入类型大全多模态AI能识别哪些内容 多模态AI支持的输入类型大全多模态AI能识别哪些内容 多模态AI支持的输入类型大全多模态AI能识别哪些内容 多模态AI支持的输入类型大全

    多模态人工智能集成了处理和理解来自不同模态信息的能力,这些模态包括但不限于文本、图像、音频、视频等。本文旨在详细阐述多模态AI能够识别和处理的内容类型,并列举其支持的主要输入形式,帮助您了解其工作原理和应用范围。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek…

    2026年10月2日 • 用户投稿
    000
  • 三星正式向更多Galaxy设备推送SamsungOne UI 8更新

    三星正式向更多Galaxy设备推送SamsungOne UI 8更新三星正式向更多Galaxy设备推送SamsungOne UI 8更新三星正式向更多Galaxy设备推送SamsungOne UI 8更新三星正式向更多Galaxy设备推送SamsungOne UI 8更新

    增强的个性化ai功能将赋能更多用户的日常生活,进一步推动ai技术的普及 2025年9月15日,三星电子正式宣布启动Samsung One UI 8系统更新推送,为更广泛的Galaxy用户群体带来升级版的多模态AI能力,以及针对不同设备形态优化的操作体验和智能个性化建议,助力打造更加智慧、高效的日常使…

    2026年10月2日 • 用户投稿
    000
  • Yii框架中的模型关系:实现数据关联

    在%ignore_a_1%框架中,模型关系是一个非常重要的概念,用于实现多个数据表之间的数据关联。通过定义关联关系,可以使得在查询数据时,可以直接获取到相关联的数据,从而大大降低查询复杂度,提高数据查询效率。本文将详细介绍yii框架中的模型关系,包括如何定义关联关系、不同类型的关联关系以及如何使用关…

    用户投稿 2026年10月2日
    000
  • 硬盘数据恢复贵吗?如何用低成本恢复丢失的数据?

    硬盘数据恢复贵吗?如何用低成本恢复丢失的数据?硬盘数据恢复贵吗?如何用低成本恢复丢失的数据?硬盘数据恢复贵吗?如何用低成本恢复丢失的数据?硬盘数据恢复贵吗?如何用低成本恢复丢失的数据?

    数据恢复价格因难度而异,首先应停止使用硬盘以防覆盖数据,检查连接后尝试用Recuva、EaseUS等软件恢复;若硬盘有物理损坏需创建镜像或送专业实验室;预防则靠定期备份、RAID、监控SMART状态及安全操作。 硬盘数据恢复的价格差异很大,主要取决于数据丢失的严重程度和恢复的复杂性。自己动手尝试恢复…

    2026年10月2日 • 用户投稿
    000
  • Spring Boot多数据源JPA配置与原生查询实践

    Spring Boot多数据源JPA配置与原生查询实践Spring Boot多数据源JPA配置与原生查询实践Spring Boot多数据源JPA配置与原生查询实践Spring Boot多数据源JPA配置与原生查询实践

    本文详细介绍了在Spring Boot应用中配置和管理多个JPA数据源的方法,特别聚焦于如何解决在使用原生SQL查询时可能遇到的“表不存在”问题。通过引入PersistenceUnitName明确绑定EntityManager到特定数据源,并结合@EnableJpaRepositories和@Tra…

    2026年10月2日 • 用户投稿
    000
  • 如何开发多模态AI应用 多模态AI开发入门指南与工具推荐

    如何开发多模态AI应用 多模态AI开发入门指南与工具推荐如何开发多模态AI应用 多模态AI开发入门指南与工具推荐如何开发多模态AI应用 多模态AI开发入门指南与工具推荐如何开发多模态AI应用 多模态AI开发入门指南与工具推荐

    多模态人工智能旨在融合并理解来自不同源的数据,如文本、图像、音频和视频,从而构建更具洞察力和交互性的智能系统。本文将为您提供一个多模态AI开发的入门指南,从基本概念、核心开发步骤到实用的工具和框架推荐,旨在帮助您快速了解并启动您的多模态AI项目,理解如何将不同类型的数据协同用于解决复杂问题。 ☞☞☞…

    2026年10月2日 • 用户投稿
    200
  • 多模态AI如何处理视频 视频内容分析与理解技术详解

    多模态AI如何处理视频 视频内容分析与理解技术详解多模态AI如何处理视频 视频内容分析与理解技术详解多模态AI如何处理视频 视频内容分析与理解技术详解多模态AI如何处理视频 视频内容分析与理解技术详解

    多模态AI处理视频是一个复杂而精妙的过程,旨在深入理解视频内容。这不仅仅是观看图像序列,更结合了视觉、听觉甚至文本等多种信息来源进行综合分析。本文将详细阐述多模态AI如何分步骤地实现视频内容的分析与理解,帮助您了解其核心技术和操作流程。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限…

    2026年10月2日 • 用户投稿
    000
  • 检测 Java 中对象是否为 Kotlin 数组

    检测 Java 中对象是否为 Kotlin 数组检测 Java 中对象是否为 Kotlin 数组检测 Java 中对象是否为 Kotlin 数组检测 Java 中对象是否为 Kotlin 数组

    本文旨在解决在 Java 代码中检测 Kotlin 数组的问题,尤其是在处理 Kotlin 注解时遇到的类型差异。通过分析 Kotlin 数组在 JVM 层的表示,以及注解代理对象的特性,提供一种可靠的检测方法,并避免常见的误判。 在 Java 和 Kotlin 混合编程环境中,处理注解时可能会遇到…

    2026年10月2日 • 用户投稿
    100
  • 掌握SQL中JOIN、WHERE和ORDER BY的组合使用技巧

    本文详细阐述了在SQL查询中同时使用JOIN、WHERE和ORDER BY子句的正确语法和逻辑顺序。重点强调了ON子句应紧随其关联的JOIN操作之后,以及WHERE子句必须位于ORDER BY子句之前,以确保查询的准确性和效率。通过具体示例,帮助读者构建结构清晰、功能完善的SQL查询语句。 SQL查…

    2026年10月2日
    100
  • Spring Boot多数据库JPA原生查询配置指南

    Spring Boot多数据库JPA原生查询配置指南Spring Boot多数据库JPA原生查询配置指南Spring Boot多数据库JPA原生查询配置指南Spring Boot多数据库JPA原生查询配置指南

    本教程详细探讨了在Spring Boot应用中配置多个JPA数据源时,原生查询可能遇到的指向错误问题。当配置了主次两个PostgreSQL数据库,且在次要数据库上执行JPA原生SQL查询时,系统可能错误地将查询路由到主数据库。核心解决方案在于利用@PersistenceContext注解的unitN…

    2026年10月2日 • 用户投稿
    200
  • 2025腾讯全球数字生态大会:“AI百校行”正式启动,助力高校学子铸造未来竞争力

    2025腾讯全球数字生态大会:“AI百校行”正式启动,助力高校学子铸造未来竞争力2025腾讯全球数字生态大会:“AI百校行”正式启动,助力高校学子铸造未来竞争力2025腾讯全球数字生态大会:“AI百校行”正式启动,助力高校学子铸造未来竞争力2025腾讯全球数字生态大会:“AI百校行”正式启动,助力高校学子铸造未来竞争力

    ai时代的应用落地和价值深耕,既依赖于技术的飞速进步,更离不开生态伙伴开放共建。 9月16日,在2025腾讯全球数字生态大会上,为加速AI在千行百业落地进程及创新人才培养,腾讯正式发起“AI应用繁荣计划”,其中面向全国高校人才培养与素养提升的“AI百校行”同步启动;结合腾讯领先的AI技术和离产业最近…

    2026年10月2日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信