不能并发的给 socket 发消息,竟然导致panic还退出应用,不仅仅是退出函数
panic: concurrent write to websocket connection
解决方案:
https://blog.csdn.net/qq_40374604/article/details/139141664
package main
import (
"log"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// 定义一个结构体来包含WebSocket连接和互斥锁
type WebSocketConnection struct {
Conn *websocket.Conn
Lock sync.Mutex
}
func handleConnections(ws *websocket.Conn) {
defer ws.Close()
log.Println("Connection established")
// 创建WebSocketConnection实例
conn := &WebSocketConnection{
Conn: ws,
Lock: sync.Mutex{},
}
// Ping goroutine
go func() {
for {
// 使用互斥锁来同步写操作
conn.Lock()
if err := ws.WriteMessage(websocket.PingMessage, nil); err != nil {
log.Println("Failed to send Ping: ", err)
return
}
conn.Unlock()
time.Sleep(10 * time.Second)
}
}()
// 消息处理goroutine
go func() {
// 这里可以处理接收到的消息等
// ...
}()
// 这里可以添加更多的goroutine来处理不同的任务
// ...
}
func main() {
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade:", err)
return
}
go handleConnections(ws)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
充值导致用户余额翻倍
原因:用户充值后,用gorm事务将充值订单存入订单数据表,同步修改用户余额表,因为页面要轮询检查用户是否完成扫码充值,在服务端发给微信服务器的接口里,做了存储充值记录(订单)和修改用户余额的动作,而服务端轮询接口里,一旦成功,也做了二次存入订单以及修改用户余额的动作,但是后者,存入订单动作做了唯一性判断,即firstorcreate,因为订单可以做唯一性判断,但是余额只有一条,通过不断修改(update)来实现,没有办法通过唯一性来判断是否重复修改。所以,在策略上,应该是当判断订单已经存在后,则不修改用户余额了,因为存订单和修改余额是用了事务,所以说明在之前存订单的时候,余额是修改成功的,否则订单也就是发生存入错误。
// 新建充值
result := tx.FirstOrCreate(&wxuserrecharge, WxUserRecharge{OutTradeNo: outtradeno, TransactionId: transactionid})
err = result.Error
if err != nil {
tx.Rollback()
return err
}
// 如果没找到,就创建一个新纪录
// result := db.FirstOrCreate(&user, User{Name: "non_existing"})
// SQL: INSERT INTO "users" (name) VALUES ("non_existing");
// user -> User{ID: 112, Name: "non_existing"}
// result.RowsAffected // => 1 (record created)
// 如果已经存在这个充值订单,则不更新后面的用户余额了,说明之前已经更新过了。
if result.RowsAffected == 0 {
tx.Rollback() // 这一句如果漏了,就会发生锁库
return err
}
// 新建或更新余额
var wxuserbalance WxUserBalance
//没有查到则新增一条余额
err = tx.FirstOrCreate(&wxuserbalance, WxUserBalance{UserID: uid}).Error
if err != nil {
tx.Rollback()
return err
}
newamount := wxuserbalance.Amount + amount
rowsAffected := tx.Model(&wxuserbalance).Update("amount", newamount).RowsAffected
if rowsAffected == 0 {
tx.Rollback()
return err
}
return tx.Commit().Error
作者:秦晓川 创建时间:2025-02-09 16:21
最后编辑:秦晓川 更新时间:2025-03-06 09:52
最后编辑:秦晓川 更新时间:2025-03-06 09:52