7.6 KiB
7.6 KiB
数据库使用指南
📋 概述
SunHPC 使用 SQLite 数据库,支持自定义数据库路径和名称。数据库配置通过 sunhpc init database 命令初始化,之后所有命令都可以通过单例模式访问同一个数据库实例。
🚀 快速开始
1. 初始化数据库
# 使用默认路径 (/var/lib/sunhpc/sunhpc.db)
sunhpc init database
# 使用自定义配置文件
sunhpc init database --config /path/to/config.yaml
# 使用环境变量
DB_PATH=/opt/sunhpc/data DB_NAME=cluster.db sunhpc init database
# 强制重新初始化
sunhpc init database --force
2. 在其他命令中使用数据库
package cmd
import (
"fmt"
"sunhpc/internal/db"
"sunhpc/internal/log"
"github.com/spf13/cobra"
)
var myCmd = &cobra.Command{
Use: "mycommand",
Short: "我的命令",
RunE: func(cmd *cobra.Command, args []string) error {
// 获取数据库实例(自动使用配置的路径)
database, err := db.GetInstance()
if err != nil {
return fmt.Errorf("获取数据库连接失败: %v", err)
}
defer database.Close()
// 执行查询
_, err = database.Execute("SELECT * FROM nodes")
if err != nil {
return fmt.Errorf("查询失败: %v", err)
}
// 获取结果
rows, err := database.FetchAll()
if err != nil {
return fmt.Errorf("获取结果失败: %v", err)
}
// 处理结果
for _, row := range rows {
log.Infof("节点: %v", row)
}
return nil
},
}
🔧 配置说明
配置文件格式
创建 config.yaml 文件:
db:
path: "/opt/sunhpc/data" # 数据库目录路径
name: "my_cluster.db" # 数据库文件名
配置优先级
从高到低:
- 配置文件:
config.yaml中的db.path和db.name - 环境变量:
DB_PATH和DB_NAME - 默认值:
/var/lib/sunhpc和sunhpc.db
环境变量
# 设置数据库路径
export DB_PATH=/tmp/sunhpc
export DB_NAME=test.db
# 使用环境变量
sunhpc init database
📊 数据库 API
获取数据库实例
// 方式1:使用默认配置(推荐)
database, err := db.GetInstance()
// 方式2:指定路径和名称(仅在初始化时使用)
database, err := db.GetInstanceWithConfig("/path/to/db", "mydb.db")
// 检查实例是否已配置
if db.IsInstanceConfigured() {
dbPath, dbName := db.GetInstanceConfig()
log.Infof("数据库: %s/%s", dbPath, dbName)
}
执行 SQL
// 执行查询
_, err := database.Execute("SELECT * FROM nodes WHERE name = ?", "node1")
// 执行插入
_, err := database.Execute(
"INSERT INTO nodes (name, cpus, memory) VALUES (?, ?, ?)",
"node2", 32, 128,
)
// 执行更新
_, err := database.Execute(
"UPDATE nodes SET cpus = ? WHERE name = ?",
64, "node1",
)
// 执行删除
_, err := database.Execute("DELETE FROM nodes WHERE name = ?", "node1")
获取查询结果
// 获取单行
row, err := database.FetchOne()
if err != nil {
return err
}
if row != nil {
log.Infof("节点名称: %s", row["name"])
log.Infof("CPU数量: %v", row["cpus"])
}
// 获取所有行
rows, err := database.FetchAll()
if err != nil {
return err
}
for _, row := range rows {
log.Infof("节点: %v", row)
}
🎯 使用示例
示例1:查询节点列表
func listNodes() error {
database, err := db.GetInstance()
if err != nil {
return err
}
defer database.Close()
_, err = database.Execute("SELECT id, name, cpus, memory FROM nodes ORDER BY name")
if err != nil {
return err
}
rows, err := database.FetchAll()
if err != nil {
return err
}
for _, row := range rows {
fmt.Printf("%-5s %-20s %-8s %-10s\n",
row["id"], row["name"], row["cpus"], row["memory"])
}
return nil
}
示例2:添加节点
func addNode(name string, cpus, memory int) error {
database, err := db.GetInstance()
if err != nil {
return err
}
defer database.Close()
_, err = database.Execute(
"INSERT INTO nodes (name, cpus, memory) VALUES (?, ?, ?)",
name, cpus, memory,
)
if err != nil {
return fmt.Errorf("添加节点失败: %v", err)
}
return nil
}
示例3:更新节点
func updateNode(name string, cpus, memory int) error {
database, err := db.GetInstance()
if err != nil {
return err
}
defer database.Close()
_, err = database.Execute(
"UPDATE nodes SET cpus = ?, memory = ? WHERE name = ?",
cpus, memory, name,
)
if err != nil {
return fmt.Errorf("更新节点失败: %v", err)
}
return nil
}
示例4:删除节点
func deleteNode(name string) error {
database, err := db.GetInstance()
if err != nil {
return err
}
defer database.Close()
_, err = database.Execute("DELETE FROM nodes WHERE name = ?", name)
if err != nil {
return fmt.Errorf("删除节点失败: %v", err)
}
return nil
}
🔍 数据库表结构
nodes 表
CREATE TABLE nodes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
rack INTEGER DEFAULT 0,
rank INTEGER DEFAULT 0,
membership_id INTEGER,
cpus INTEGER DEFAULT 0,
memory INTEGER DEFAULT 0,
disk INTEGER DEFAULT 0,
os TEXT,
kernel TEXT,
last_state_change DATETIME DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
networks 表
CREATE TABLE networks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
node_id INTEGER NOT NULL,
name TEXT,
ip TEXT UNIQUE,
mac TEXT UNIQUE,
subnet_id INTEGER,
interface TEXT DEFAULT 'eth0',
FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE,
FOREIGN KEY (subnet_id) REFERENCES subnets(id) ON DELETE SET NULL
);
software_installs 表
CREATE TABLE software_installs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
version TEXT,
install_type TEXT,
node_id INTEGER,
status TEXT,
installed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
installed_by TEXT,
FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE SET NULL
);
⚠️ 注意事项
- 单例模式:
GetInstance()使用单例模式,整个程序只创建一个数据库实例 - 路径一致性:所有命令都使用同一个数据库路径,确保数据一致性
- 关闭连接:使用完毕后调用
database.Close()释放资源 - 错误处理:始终检查错误返回值
- SQL注入防护:使用参数化查询(
?占位符)
📝 最佳实践
- 初始化优先:在程序启动时先执行
sunhpc init database - 配置管理:使用配置文件统一管理数据库路径
- 事务处理:复杂操作使用事务确保数据一致性
- 日志记录:记录所有数据库操作,便于调试
- 资源释放:使用
defer database.Close()确保连接关闭
🆘 常见问题
Q: 如何切换数据库路径?
A: 重新运行 sunhpc init database 命令,指定新的配置文件或环境变量。
Q: 多个命令会创建多个数据库实例吗?
A: 不会。GetInstance() 使用单例模式,整个程序只创建一个实例。
Q: 如何查看当前使用的数据库路径?
A: 使用 db.GetInstanceConfig() 获取配置信息。
Q: 数据库文件不存在会怎样?
A: 首次调用 GetInstance() 时会自动创建数据库文件和表结构。