Golang中从数据库获取数据的最佳方法是什么
Golang中从数据库获取数据的最佳方法是什么 你好,我们正在用Go语言开发一个基于Linux服务器的软件,并且我们正在为该软件添加许可证功能。我们想请教一下,从数据库获取数据的最佳方法是什么,以及我们应该使用哪种SQL数据库。
正如我们所说,我们想要添加许可证验证,并希望验证服务器IP是否在我们的数据库中获得了许可,同时还需要检查诸如许可证状态、许可证过期日期等数据。那么,最佳方法是什么?我们应该使用MySQL还是MongoDB?
2 回复
monsterlegend99:
那么,哪种方法最好,我们应该使用哪种 SQL,是 MySQL 还是 MongoDB?
MongoDB 不是 SQL。它是 NoSQL。你应该选择哪一个取决于你的数据。我更喜欢 PostgreSQL,因为我觉得它比 MySQL 更安全。
![]()
Logi Analytics
构建闪电般快速的嵌入式分析体验,同时加速实现价值——无需额外的工程资源。
更多关于Golang中从数据库获取数据的最佳方法是什么的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
对于从数据库获取数据的最佳方法,我建议使用标准库database/sql配合预处理语句和连接池。以下是具体实现方案:
数据库选择建议
使用MySQL而不是MongoDB,原因如下:
- 许可证数据是结构化关系型数据
- 需要事务支持确保数据一致性
- SQL查询更适合复杂的条件检查
最佳实践代码示例
package main
import (
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
type License struct {
ID int
ServerIP string
Status string
ExpiryDate time.Time
MaxUsers int
LicenseKey string
}
type LicenseManager struct {
db *sql.DB
}
// 初始化数据库连接
func NewLicenseManager(dsn string) (*LicenseManager, error) {
db, err := sql.Open("mysql", dsn)
if err != nil {
return nil, err
}
// 配置连接池
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
// 验证连接
if err := db.Ping(); err != nil {
return nil, err
}
return &LicenseManager{db: db}, nil
}
// 使用预处理语句获取许可证数据
func (lm *LicenseManager) ValidateLicense(serverIP, licenseKey string) (*License, error) {
query := `
SELECT id, server_ip, status, expiry_date, max_users, license_key
FROM licenses
WHERE server_ip = ? AND license_key = ? AND status = 'active'
`
var license License
row := lm.db.QueryRow(query, serverIP, licenseKey)
err := row.Scan(
&license.ID,
&license.ServerIP,
&license.Status,
&license.ExpiryDate,
&license.MaxUsers,
&license.LicenseKey,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, fmt.Errorf("license not found or inactive")
}
return nil, err
}
// 检查过期日期
if license.ExpiryDate.Before(time.Now()) {
return nil, fmt.Errorf("license expired")
}
return &license, nil
}
// 批量查询多个许可证状态
func (lm *LicenseManager) CheckMultipleLicenses(serverIPs []string) (map[string]bool, error) {
query := `
SELECT server_ip
FROM licenses
WHERE server_ip IN (`
// 构建IN查询参数
args := make([]interface{}, len(serverIPs))
for i, ip := range serverIPs {
if i > 0 {
query += ","
}
query += "?"
args[i] = ip
}
query += ") AND status = 'active' AND expiry_date > NOW()"
rows, err := lm.db.Query(query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
validLicenses := make(map[string]bool)
for rows.Next() {
var ip string
if err := rows.Scan(&ip); err != nil {
return nil, err
}
validLicenses[ip] = true
}
return validLicenses, nil
}
// 使用事务更新许可证状态
func (lm *LicenseManager) UpdateLicenseStatus(licenseID int, newStatus string) error {
tx, err := lm.db.Begin()
if err != nil {
return err
}
defer func() {
if err != nil {
tx.Rollback()
}
}()
// 更新许可证状态
_, err = tx.Exec(
"UPDATE licenses SET status = ?, updated_at = NOW() WHERE id = ?",
newStatus, licenseID,
)
if err != nil {
return err
}
// 记录状态变更日志
_, err = tx.Exec(
"INSERT INTO license_logs (license_id, old_status, new_status) VALUES (?, ?, ?)",
licenseID, "active", newStatus,
)
if err != nil {
return err
}
return tx.Commit()
}
func main() {
// 数据库连接DSN
dsn := "user:password@tcp(localhost:3306)/license_db?parseTime=true"
lm, err := NewLicenseManager(dsn)
if err != nil {
log.Fatal(err)
}
defer lm.db.Close()
// 验证许可证示例
license, err := lm.ValidateLicense("192.168.1.100", "ABC123-XYZ456")
if err != nil {
log.Printf("License validation failed: %v", err)
} else {
log.Printf("Valid license: %+v", license)
}
}
数据库表结构示例
CREATE TABLE licenses (
id INT PRIMARY KEY AUTO_INCREMENT,
server_ip VARCHAR(45) NOT NULL,
license_key VARCHAR(100) NOT NULL UNIQUE,
status ENUM('active', 'suspended', 'expired') DEFAULT 'active',
expiry_date DATETIME NOT NULL,
max_users INT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_server_ip (server_ip),
INDEX idx_expiry_status (expiry_date, status)
);
CREATE TABLE license_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
license_id INT NOT NULL,
old_status VARCHAR(50),
new_status VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (license_id) REFERENCES licenses(id)
);
关键要点
- 使用连接池:合理配置
SetMaxOpenConns和SetMaxIdleConns - 预处理语句:防止SQL注入,提高性能
- 错误处理:正确处理
sql.ErrNoRows - 事务支持:确保数据一致性
- 索引优化:在
server_ip、expiry_date和status字段上创建索引
这种方法结合了性能、安全性和可维护性,特别适合许可证验证这类需要高可靠性的场景。

