ok-1
This commit is contained in:
344
docs/database_usage.md
Normal file
344
docs/database_usage.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# 数据库使用指南
|
||||
|
||||
## 📋 概述
|
||||
|
||||
SunHPC 使用 SQLite 数据库,支持自定义数据库路径和名称。数据库配置通过 `sunhpc init database` 命令初始化,之后所有命令都可以通过单例模式访问同一个数据库实例。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 初始化数据库
|
||||
|
||||
```bash
|
||||
# 使用默认路径 (/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. 在其他命令中使用数据库
|
||||
|
||||
```go
|
||||
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` 文件:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
path: "/opt/sunhpc/data" # 数据库目录路径
|
||||
name: "my_cluster.db" # 数据库文件名
|
||||
```
|
||||
|
||||
### 配置优先级
|
||||
|
||||
从高到低:
|
||||
|
||||
1. **配置文件**:`config.yaml` 中的 `db.path` 和 `db.name`
|
||||
2. **环境变量**:`DB_PATH` 和 `DB_NAME`
|
||||
3. **默认值**:`/var/lib/sunhpc` 和 `sunhpc.db`
|
||||
|
||||
### 环境变量
|
||||
|
||||
```bash
|
||||
# 设置数据库路径
|
||||
export DB_PATH=/tmp/sunhpc
|
||||
export DB_NAME=test.db
|
||||
|
||||
# 使用环境变量
|
||||
sunhpc init database
|
||||
```
|
||||
|
||||
## 📊 数据库 API
|
||||
|
||||
### 获取数据库实例
|
||||
|
||||
```go
|
||||
// 方式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
|
||||
|
||||
```go
|
||||
// 执行查询
|
||||
_, 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")
|
||||
```
|
||||
|
||||
### 获取查询结果
|
||||
|
||||
```go
|
||||
// 获取单行
|
||||
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:查询节点列表
|
||||
|
||||
```go
|
||||
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:添加节点
|
||||
|
||||
```go
|
||||
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:更新节点
|
||||
|
||||
```go
|
||||
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:删除节点
|
||||
|
||||
```go
|
||||
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 表
|
||||
|
||||
```sql
|
||||
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 表
|
||||
|
||||
```sql
|
||||
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 表
|
||||
|
||||
```sql
|
||||
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
|
||||
);
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **单例模式**:`GetInstance()` 使用单例模式,整个程序只创建一个数据库实例
|
||||
2. **路径一致性**:所有命令都使用同一个数据库路径,确保数据一致性
|
||||
3. **关闭连接**:使用完毕后调用 `database.Close()` 释放资源
|
||||
4. **错误处理**:始终检查错误返回值
|
||||
5. **SQL注入防护**:使用参数化查询(`?` 占位符)
|
||||
|
||||
## 📝 最佳实践
|
||||
|
||||
1. **初始化优先**:在程序启动时先执行 `sunhpc init database`
|
||||
2. **配置管理**:使用配置文件统一管理数据库路径
|
||||
3. **事务处理**:复杂操作使用事务确保数据一致性
|
||||
4. **日志记录**:记录所有数据库操作,便于调试
|
||||
5. **资源释放**:使用 `defer database.Close()` 确保连接关闭
|
||||
|
||||
## 🆘 常见问题
|
||||
|
||||
### Q: 如何切换数据库路径?
|
||||
|
||||
A: 重新运行 `sunhpc init database` 命令,指定新的配置文件或环境变量。
|
||||
|
||||
### Q: 多个命令会创建多个数据库实例吗?
|
||||
|
||||
A: 不会。`GetInstance()` 使用单例模式,整个程序只创建一个实例。
|
||||
|
||||
### Q: 如何查看当前使用的数据库路径?
|
||||
|
||||
A: 使用 `db.GetInstanceConfig()` 获取配置信息。
|
||||
|
||||
### Q: 数据库文件不存在会怎样?
|
||||
|
||||
A: 首次调用 `GetInstance()` 时会自动创建数据库文件和表结构。
|
||||
Reference in New Issue
Block a user