Golang中基于本地存储的队列查询表问题如何解决?
Golang中基于本地存储的队列查询表问题如何解决? 我正在尝试使用Go和PostgreSQL创建一个SQL查询的查找表。这是一种非传统的方法来解决涉及多个查询的问题,所以可能方向不对。
下面的代码在少量调用计算机上可以正常工作,但由于每次调用最终都会在查找数据库的单个会话中进行,我担心这可能会导致未来查找排队的问题。
这是对REST API with 1000 query templates的后续问题。
我为仅两个查找设置了测试服务器:
http://94.237.25.207:8099/co
http://94.237.25.207:8099/pe
package main
import (
"fmt"
"log"
"strings"
"net/http"
"database/sql"
_ "github.com/lib/pq"
)
var db *sql.DB
var err error
func main() {
http.HandleFunc("/", Query)
Connect()
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Connect() {
const (
host = "127.0.0.1"
port = 5432
user = "go"
password = "test"
dbname = "lookup")
login := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
var err error
db, err = sql.Open("postgres", login)
if err != nil {
log.Fatalln(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
}
func Query (w http.ResponseWriter, r *http.Request){
id := strings.Replace(r.URL.String(), "/", "", -1) //remove slashes
values := []string{"SELECT sqlx FROM get WHERE id =","'",id,"'"}
query := strings.Join(values, "")
var sqlx string
var row *sql.Row
row = db.QueryRow(query)
err := row.Scan(&sqlx)
if err != nil && err != sql.ErrNoRows {
log.Fatalln(err)
}
fmt.Fprintf(w,"%s", sqlx)
}
更多关于Golang中基于本地存储的队列查询表问题如何解决?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中基于本地存储的队列查询表问题如何解决?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理基于本地存储的队列查询表时,主要问题在于使用单个数据库连接处理所有请求,这确实会导致性能瓶颈和潜在的排队问题。以下是改进方案:
解决方案:使用连接池和预处理语句
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"strings"
"sync"
_ "github.com/lib/pq"
)
var db *sql.DB
var stmtCache *sync.Map
func main() {
Connect()
// 初始化语句缓存
stmtCache = &sync.Map{}
http.HandleFunc("/", Query)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Connect() {
const (
host = "127.0.0.1"
port = 5432
user = "go"
password = "test"
dbname = "lookup"
)
login := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
var err error
db, err = sql.Open("postgres", login)
if err != nil {
log.Fatalln(err)
}
// 配置连接池
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5 * time.Minute)
err = db.Ping()
if err != nil {
panic(err)
}
}
func Query(w http.ResponseWriter, r *http.Request) {
id := strings.Trim(r.URL.Path, "/")
// 使用预处理语句避免SQL注入和提高性能
sqlx, err := getSQLFromCache(id)
if err != nil {
if err == sql.ErrNoRows {
http.Error(w, "Not found", http.StatusNotFound)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
log.Printf("Query error: %v", err)
return
}
fmt.Fprintf(w, "%s", sqlx)
}
func getSQLFromCache(id string) (string, error) {
// 尝试从缓存获取预处理语句
stmtKey := "get_sql"
cachedStmt, ok := stmtCache.Load(stmtKey)
var stmt *sql.Stmt
var err error
if ok {
stmt = cachedStmt.(*sql.Stmt)
} else {
// 创建新的预处理语句
stmt, err = db.Prepare("SELECT sqlx FROM get WHERE id = $1")
if err != nil {
return "", err
}
stmtCache.Store(stmtKey, stmt)
}
var sqlx string
err = stmt.QueryRow(id).Scan(&sqlx)
return sqlx, err
}
更高级的解决方案:使用本地缓存减少数据库查询
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"sync"
"time"
_ "github.com/lib/pq"
)
var db *sql.DB
var cache *sync.Map
var cacheMutex sync.RWMutex
func main() {
Connect()
// 初始化内存缓存
cache = &sync.Map{}
// 定期刷新缓存
go refreshCache()
http.HandleFunc("/", Query)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Query(w http.ResponseWriter, r *http.Request) {
id := strings.Trim(r.URL.Path, "/")
// 首先尝试从内存缓存获取
if value, ok := cache.Load(id); ok {
fmt.Fprintf(w, "%s", value.(string))
return
}
// 缓存未命中,从数据库查询
sqlx, err := getSQLFromDB(id)
if err != nil {
if err == sql.ErrNoRows {
http.Error(w, "Not found", http.StatusNotFound)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
log.Printf("Query error: %v", err)
return
}
// 更新缓存
cache.Store(id, sqlx)
fmt.Fprintf(w, "%s", sqlx)
}
func getSQLFromDB(id string) (string, error) {
var sqlx string
err := db.QueryRow("SELECT sqlx FROM get WHERE id = $1", id).Scan(&sqlx)
return sqlx, err
}
func refreshCache() {
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for range ticker.C {
loadAllQueries()
}
}
func loadAllQueries() {
rows, err := db.Query("SELECT id, sqlx FROM get")
if err != nil {
log.Printf("Failed to refresh cache: %v", err)
return
}
defer rows.Close()
newCache := &sync.Map{}
for rows.Next() {
var id, sqlx string
if err := rows.Scan(&id, &sqlx); err != nil {
log.Printf("Failed to scan row: %v", err)
continue
}
newCache.Store(id, sqlx)
}
// 原子性替换缓存
cacheMutex.Lock()
cache = newCache
cacheMutex.Unlock()
}
关键改进点:
- 连接池配置:设置适当的连接池参数避免连接耗尽
- 预处理语句:使用参数化查询防止SQL注入和提高性能
- 内存缓存:减少对数据库的直接查询
- 错误处理:更健壮的错误处理而非直接panic
- 并发安全:使用sync.Map处理并发访问
这些改进能显著提升高并发场景下的性能,避免查询排队问题。

