添加数据到数据库,但无法插入,临时提交保存

This commit is contained in:
2026-03-06 00:29:34 +08:00
parent f7dcfa4e7d
commit 3f5e333a4d
12 changed files with 1343 additions and 440 deletions

View File

@@ -1,11 +1,8 @@
package database
import (
"bufio"
"database/sql"
"fmt"
"os"
"strings"
"sync"
"sunhpc/pkg/config"
@@ -25,10 +22,114 @@ var (
dbErr error
)
// =========================================================
// 封装数据库函数使用Go实现
// =========================================================
// MapCategory - 根据类别名称查ID
// 查询方式: globalID, err := db.MapCategory(conn, "global")
func MapCategory(conn *sql.DB, catname string) (int, error) {
var id int
query := "select id from categories where name = ?"
logger.Debugf("查询SQL: %s", query)
logger.Debugf("查询类别ID: %s", catname)
err := conn.QueryRow(query, catname).Scan(&id)
if err == sql.ErrNoRows {
logger.Debugf("未找到类别 %s, 返回ID=0", catname)
return 0, nil // 无匹配返回0
}
logger.Debugf("查询到类别 %s, ID=%d", catname, id)
return id, nil
}
// MapCategoryIndex - 根据类别名称 + 索引名称查ID
// 调用方式: linuxOSID, err := db.MapCategoryIndex(conn, "os", "linux")
func MapCategoryIndex(conn *sql.DB, catindexName, categoryIndex string) (int, error) {
var id int
query := `
select index_id from vmapCategoryIndex
where categoryName = ? and categoryIndex = ?
`
logger.Debugf("查询SQL: %s", query)
logger.Debugf("查询索引ID: %s, 类别: %s", catindexName, categoryIndex)
err := conn.QueryRow(query, catindexName, categoryIndex).Scan(&id)
if err == sql.ErrNoRows {
logger.Debugf("未找到索引 %s, 返回ID=0", catindexName)
return 0, nil // 无匹配返回0
}
logger.Debugf("查询到索引 %s, ID=%d", catindexName, id)
return id, nil
}
// ResolveFirewalls - 解析指定主机的防火墙规则
// 返回解析后的防火墙规则(fwresolved表数据),临时表使用后自动清理
// 调用方式: rows, err := db.ResolveFirewalls(conn, "compute-0-1", "default")
func ResolveFirewalls(conn *sql.DB, hostname, chainname string) (*sql.Rows, error) {
// 步骤1 创建临时表 fresolved1
_, err := conn.Exec(`
DROP TABLE IF EXISTS fresolved1;
CREATE TEMPORARY TABLE fresolved1 AS
SELECT
? AS hostname,
? AS Resolver,
f.*,
r.precedence
FROM
resolvechain r
inner join hostselections hs on r.category = hs.category and r.name = ?
inner join firewalls f on hs.category = f.category and hs.selection = f.catindex
where hs.host = ?;
`, hostname, chainname, chainname, hostname)
if err != nil {
return nil, fmt.Errorf("Create temporary table fresolved1 failed: %w", err)
}
// 步骤2创建临时表 fresolved2
_, err = conn.Exec(`
DROP TABLE IF EXISTS fresolved2;
CREATE TEMPORARY TABLE fresolved2 AS
SELECT
*
FROM
fresolved1;
`)
if err != nil {
return nil, fmt.Errorf("Create temporary table fresolved2 failed: %w", err)
}
// 步骤3创建最终结果表 fwresolved
_, err = conn.Exec(`
DROP TABLE IF EXISTS fwresolved;
CREATE TEMPORARY TABLE fwresolved AS
SELECT
r1.*,
cat.name AS categoryName
FROM
fresolved1 r1
inner join (
select Rulename, MAX(precedence) as precedence
from fresolved2
group by Rulename
) AS r2 on r1.Rulename = r2.Rulename and r1.precedence = r2.precedence
inner join categories cat on r1.category = cat.id;
`)
if err != nil {
return nil, fmt.Errorf("Create temporary table fwresolved failed: %w", err)
}
// 步骤4查询结果并返回
rows, err := conn.Query("SELECT * FROM fwresolved")
if err != nil {
return nil, fmt.Errorf("Query fwresolved failed: %w", err)
}
return rows, nil
}
// =========================================================
// GetDB - 获取数据库连接(单例模式)
// =========================================================
func GetDB() (*sql.DB, error) {
logger.Debug("获取数据库连接...")
dbOnce.Do(func() {
if dbInstance != nil {
return
@@ -75,45 +176,11 @@ func GetDB() (*sql.DB, error) {
return dbInstance, nil
}
func confirmAction(prompt string) bool {
reader := bufio.NewReader(os.Stdin)
logger.Warnf("%s [Y/Yes]: ", prompt)
response, err := reader.ReadString('\n')
if err != nil {
return false
}
response = strings.ToLower(strings.TrimSpace(response))
return response == "y" || response == "yes"
}
func InitTables(db *sql.DB, force bool) error {
if force {
// 确认是否强制删除
if !confirmAction("确认强制删除所有表和触发器?") {
logger.Info("操作已取消")
db.Close()
os.Exit(0)
return nil
}
// 强制删除所有表和触发器
logger.Debug("强制删除所有表和触发器...")
if err := dropTables(db); err != nil {
return fmt.Errorf("删除表失败: %w", err)
}
logger.Debug("删除所有表和触发器成功")
if err := dropTriggers(db); err != nil {
return fmt.Errorf("删除触发器失败: %w", err)
}
logger.Debug("删除所有触发器成功")
}
// ✅ 调用 schema.go 中的函数
for _, ddl := range CreateTableStatements() {
//for _, ddl := range CreateTableStatements() {
for _, ddl := range BaseTables() {
logger.Debugf("执行: %s", ddl)
if _, err := db.Exec(ddl); err != nil {
return fmt.Errorf("数据表创建失败: %w", err)
@@ -128,26 +195,12 @@ func InitTables(db *sql.DB, force bool) error {
select * from sqlite_master where type='table'; # 查看表定义
PRAGMA integrity_check; # 检查数据库完整性
*/
return nil
}
func dropTables(db *sql.DB) error {
// ✅ 调用 schema.go 中的函数
for _, table := range DropTableOrder() {
if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
return err
}
}
return nil
}
func dropTriggers(db *sql.DB) error {
// ✅ 调用 schema.go 中的函数
for _, trigger := range DropTriggerStatements() {
if _, err := db.Exec(fmt.Sprintf("DROP TRIGGER IF EXISTS `%s`", trigger)); err != nil {
return err
}
// 添加基础数据
if err := InitBaseData(db); err != nil {
return fmt.Errorf("初始化基础数据失败: %w", err)
}
logger.Info("基础数据初始化成功")
return nil
}
@@ -212,3 +265,64 @@ func TestNodeInsert(db *sql.DB) error {
return nil
})
}
// =========================================================
// 带事务执行 SQL 语句,自动提交/回滚
// =========================================================
// 执行单条SQL语句带事务管理
func ExecSingleWithTransaction(sqlStr string) error {
// 复用批量函数将单条SQL语句包装为数组执行
return ExecWithTransaction([]string{sqlStr})
}
// 批量执行 DDL 语句,带事务管理
func ExecWithTransaction(ddl []string) error {
conn, err := GetDB()
if err != nil {
logger.Errorf("获取数据库连接失败: %v", err)
return err
}
// 开始事务
tx, err := conn.Begin()
if err != nil {
logger.Errorf("开始事务失败: %v", err)
return err
}
// 延迟处理:如果函数异常,回滚事务
defer func() {
if r := recover(); r != nil {
// 捕获 panic 并回滚事务
tx.Rollback()
logger.Errorf("事务执行中发生 panic: %v", r)
}
}()
// 遍历执行 DDL 语句
for idx, sql := range ddl {
logger.Debugf("执行 DDL 语句 %d: %s", idx+1, sql)
_, err = tx.Exec(sql)
if err != nil {
// 执行失败时,回滚事务
rollbackErr := tx.Rollback()
if rollbackErr != nil {
logger.Errorf("执行失败: 回滚失败: %v (原错误: %v, SQL: %s)", rollbackErr, err, sql)
} else {
logger.Errorf("执行失败: 回滚事务: %v, SQL: %s", err, sql)
}
logger.Errorf("执行 %d 条, 失败: %w (SQL: %s)", idx+1, err, sql)
}
}
// 所有SQL语句执行成功提交事务
logger.Info("所有SQL语句执行成功,提交事务")
if err := tx.Commit(); err != nil {
logger.Errorf("提交事务失败: %w", err)
return err
}
logger.Debugf("成功执行 %d 条 SQL 语句, 事务已提交.", len(ddl))
return nil
}