Golang中如何在文件中执行SQL命令

Golang中如何在文件中执行SQL命令 我想将SQL命令存储在文件中并进行加密,并且能够在请求时加载。

这类似于存储过程,可以帮助我在运行时进行修改。

3 回复

我不太确定是否理解了你的需求,但这听起来有点像 MyBatis,所以请查看 mybatis – MyBatis 3 | 简介 来获取一些想法和提示…

更多关于Golang中如何在文件中执行SQL命令的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


由于 dotsql 使用文本文件,您可以使用任何您喜欢的方法对其进行加密。然后,在您的初始化或请求方法中,将加密数据作为字节获取,转换为字符串,并使用您之前使用的加密方法来解密 SQL 语句,接着使用 LoadFromString 来加载 SQL 语句。

在Golang中执行文件中的SQL命令可以通过以下方式实现:

1. 读取并执行SQL文件的基本方法

package main

import (
    "database/sql"
    "fmt"
    "io/ioutil"
    "log"
    _ "github.com/lib/pq" // PostgreSQL驱动
)

func executeSQLFromFile(db *sql.DB, filename string) error {
    // 读取SQL文件
    sqlBytes, err := ioutil.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("读取文件失败: %v", err)
    }
    
    sqlContent := string(sqlBytes)
    
    // 执行SQL命令
    _, err = db.Exec(sqlContent)
    if err != nil {
        return fmt.Errorf("执行SQL失败: %v", err)
    }
    
    return nil
}

func main() {
    db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    err = executeSQLFromFile(db, "queries.sql")
    if err != nil {
        log.Fatal(err)
    }
}

2. 加密SQL文件并动态解密执行

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "database/sql"
    "encoding/base64"
    "fmt"
    "io"
    "io/ioutil"
    "log"
)

// 加密SQL文件
func encryptSQLFile(inputFile, outputFile string, key []byte) error {
    plaintext, err := ioutil.ReadFile(inputFile)
    if err != nil {
        return err
    }
    
    block, err := aes.NewCipher(key)
    if err != nil {
        return err
    }
    
    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return err
    }
    
    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
    
    return ioutil.WriteFile(outputFile, ciphertext, 0644)
}

// 解密并执行SQL
func executeEncryptedSQL(db *sql.DB, encryptedFile string, key []byte) error {
    ciphertext, err := ioutil.ReadFile(encryptedFile)
    if err != nil {
        return err
    }
    
    block, err := aes.NewCipher(key)
    if err != nil {
        return err
    }
    
    if len(ciphertext) < aes.BlockSize {
        return fmt.Errorf("密文太短")
    }
    
    iv := ciphertext[:aes.BlockSize]
    ciphertext = ciphertext[aes.BlockSize:]
    
    stream := cipher.NewCFBDecrypter(block, iv)
    stream.XORKeyStream(ciphertext, ciphertext)
    
    sqlContent := string(ciphertext)
    
    // 执行解密后的SQL
    _, err = db.Exec(sqlContent)
    return err
}

func main() {
    key := []byte("32-byte-key-for-AES-256-encryption!")
    
    // 加密SQL文件
    err := encryptSQLFile("original.sql", "encrypted.sql", key)
    if err != nil {
        log.Fatal(err)
    }
    
    // 连接数据库
    db, err := sql.Open("postgres", "connection_string")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    // 执行加密的SQL
    err = executeEncryptedSQL(db, "encrypted.sql", key)
    if err != nil {
        log.Fatal(err)
    }
}

3. 支持多条SQL语句和事务处理

package main

import (
    "database/sql"
    "fmt"
    "strings"
    "io/ioutil"
)

func executeMultipleSQLFromFile(db *sql.DB, filename string) error {
    content, err := ioutil.ReadFile(filename)
    if err != nil {
        return err
    }
    
    // 按分号分割SQL语句
    sqlStatements := strings.Split(string(content), ";")
    
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()
    
    for _, stmt := range sqlStatements {
        stmt = strings.TrimSpace(stmt)
        if stmt == "" {
            continue
        }
        
        _, err := tx.Exec(stmt)
        if err != nil {
            return fmt.Errorf("执行SQL失败: %v\nSQL: %s", err, stmt)
        }
    }
    
    return tx.Commit()
}

// 使用示例
func main() {
    // 假设已有数据库连接
    // err := executeMultipleSQLFromFile(db, "queries.sql")
}

4. 带缓存的SQL文件加载器

package main

import (
    "crypto/sha256"
    "database/sql"
    "encoding/hex"
    "fmt"
    "io/ioutil"
    "sync"
    "time"
)

type SQLFileExecutor struct {
    cache     map[string]string
    cacheTime map[string]time.Time
    mutex     sync.RWMutex
    key       []byte
}

func NewSQLFileExecutor(encryptionKey []byte) *SQLFileExecutor {
    return &SQLFileExecutor{
        cache:     make(map[string]string),
        cacheTime: make(map[string]time.Time),
        key:       encryptionKey,
    }
}

func (s *SQLFileExecutor) getFileHash(filename string) (string, error) {
    content, err := ioutil.ReadFile(filename)
    if err != nil {
        return "", err
    }
    
    hash := sha256.Sum256(content)
    return hex.EncodeToString(hash[:]), nil
}

func (s *SQLFileExecutor) ExecuteSQL(db *sql.DB, filename string) error {
    s.mutex.RLock()
    cachedSQL, exists := s.cache[filename]
    cacheTime, timeExists := s.cacheTime[filename]
    s.mutex.RUnlock()
    
    currentHash, err := s.getFileHash(filename)
    if err != nil {
        return err
    }
    
    // 检查缓存是否有效(5分钟有效期)
    if exists && timeExists && time.Since(cacheTime) < 5*time.Minute {
        _, err = db.Exec(cachedSQL)
        return err
    }
    
    // 读取并解密文件
    content, err := ioutil.ReadFile(filename)
    if err != nil {
        return err
    }
    
    // 这里可以添加解密逻辑
    sqlContent := string(content) // 实际使用时应解密
    
    s.mutex.Lock()
    s.cache[filename] = sqlContent
    s.cacheTime[filename] = time.Now()
    s.mutex.Unlock()
    
    _, err = db.Exec(sqlContent)
    return err
}

这些示例展示了如何在Golang中读取、加密、解密和执行文件中的SQL命令。可以根据具体需求选择合适的加密算法和缓存策略。

回到顶部