Exemplos de Operações de Banco de Dados Web Go

Exemplos de operações de banco de dados Web Go incluindo conexões SQLite, consultas SQL e tratamento de transações

💻 Tratamento de Transações go

undefined advanced ⭐⭐⭐⭐

Gerenciar transações de banco de dados com begin, commit, rollback e níveis de isolamento

⏱️ 40 min 🏷️ go, web, database, transactions
Prerequisites: Advanced Go, database/sql package, transaction concepts
// Web Go Transaction Handling Examples
// ACID transactions and proper error handling

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

// 1. Basic Transaction

// ExecuteInTransaction executes function within transaction
func ExecuteInTransaction(db *sql.DB, fn func(*sql.Tx) error) error {
	tx, err := db.Begin()
	if err != nil {
		return fmt.Errorf("error beginning transaction: %v", err)
	}

	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
			panic(r) // re-panic after rollback
		}
	}()

	if err := fn(tx); err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			return fmt.Errorf("error: %v, rollback error: %v", err, rbErr)
		}
		return err
	}

	return tx.Commit()
}

// TransferFunds transfers money between accounts with transaction
func TransferFunds(db *sql.DB, fromAccount, toAccount int, amount float64) error {
	return ExecuteInTransaction(db, func(tx *sql.Tx) error {
		// Check sender balance
		var balance float64
		err := tx.QueryRow("SELECT balance FROM accounts WHERE id = ?", fromAccount).
			Scan(&balance)
		if err != nil {
			return fmt.Errorf("sender account not found")
		}

		if balance < amount {
			return fmt.Errorf("insufficient funds")
		}

		// Deduct from sender
		_, err = tx.Exec(`
			UPDATE accounts
			SET balance = balance - ?
			WHERE id = ?
		`, amount, fromAccount)
		if err != nil {
			return fmt.Errorf("error deducting from sender: %v", err)
		}

		// Add to receiver
		_, err = tx.Exec(`
			UPDATE accounts
			SET balance = balance + ?
			WHERE id = ?
		`, amount, toAccount)
		if err != nil {
			return fmt.Errorf("error adding to receiver: %v", err)
		}

		// Record transaction
		_, err = tx.Exec(`
			INSERT INTO transactions (from_account, to_account, amount)
			VALUES (?, ?, ?)
		`, fromAccount, toAccount, amount)
		if err != nil {
			return fmt.Errorf("error recording transaction: %v", err)
		}

		return nil
	})
}

// 2. Nested Transactions (Savepoints)

// ExecuteWithSavepoint executes operation with savepoint
func ExecuteWithSavepoint(tx *sql.Tx, savepointName string, fn func(*sql.Tx) error) error {
	_, err := tx.Exec(fmt.Sprintf("SAVEPOINT %s", savepointName))
	if err != nil {
		return fmt.Errorf("error creating savepoint: %v", err)
	}

	if err := fn(tx); err != nil {
		_, rbErr := tx.Exec(fmt.Sprintf("ROLLBACK TO SAVEPOINT %s", savepointName))
		if rbErr != nil {
			return fmt.Errorf("error: %v, rollback error: %v", err, rbErr)
		}
		return err
	}

	_, err = tx.Exec(fmt.Sprintf("RELEASE SAVEPOINT %s", savepointName))
	return err
}

// BatchUpdateWithSavepoints updates multiple records with savepoints
func BatchUpdateWithSavepoints(db *sql.DB, updates []struct{ ID int; Value string }) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	for i, update := range updates {
		savepoint := fmt.Sprintf("sp%d", i)
		err := ExecuteWithSavepoint(tx, savepoint, func(tx *sql.Tx) error {
			_, err := tx.Exec(`
				UPDATE products
				SET description = ?
				WHERE id = ?
			`, update.Value, update.ID)
			return err
		})
		if err != nil {
			log.Printf("Warning: update %d failed: %v (continuing)
", i, err)
		}
	}

	return tx.Commit()
}

// 3. Transaction Isolation Levels

// SetIsolationLevel sets transaction isolation level
func SetIsolationLevel(db *sql.DB, level string) error {
	// SQLite has limited isolation level support
	// By default, it uses SERIALIZABLE
	query := fmt.Sprintf("PRAGMA read_uncommitted = %t", level == "READ UNCOMMITTED")
	_, err := db.Exec(query)
	return err
}

// BeginReadOnlyTransaction begins read-only transaction
func BeginReadOnlyTransaction(db *sql.DB) (*sql.Tx, error) {
	return db.BeginTx(&sql.TxOptions{
		Isolation: sql.LevelSerializable,
		ReadOnly:  true,
	})
}

// 4. Transaction Patterns

// CreateOrderWithItems creates order with items in transaction
func CreateOrderWithItems(db *sql.DB, userID int, items []struct{ ProductID, Quantity int; Price float64 }) (int64, error) {
	var orderID int64

	err := ExecuteInTransaction(db, func(tx *sql.Tx) error {
		// Create order
		result, err := tx.Exec(`
			INSERT INTO orders (user_id, total_amount, status)
			VALUES (?, 0, 'pending')
		`, userID)
		if err != nil {
			return fmt.Errorf("error creating order: %v", err)
		}

		orderID, err = result.LastInsertId()
		if err != nil {
			return err
		}

		// Add items and update total
		var totalAmount float64
		for _, item := range items {
			itemTotal := float64(item.Quantity) * item.Price
			totalAmount += itemTotal

			// Insert order item
			_, err = tx.Exec(`
				INSERT INTO order_items (order_id, product_id, quantity, price)
				VALUES (?, ?, ?, ?)
			`, orderID, item.ProductID, item.Quantity, item.Price)
			if err != nil {
				return fmt.Errorf("error adding item: %v", err)
			}

			// Update product quantity
			_, err = tx.Exec(`
				UPDATE products
				SET quantity = quantity - ?
				WHERE id = ? AND quantity >= ?
			`, item.Quantity, item.ProductID, item.Quantity)
			if err != nil {
				return fmt.Errorf("error updating product: %v", err)
			}
		}

		// Update order total
		_, err = tx.Exec(`
			UPDATE orders
			SET total_amount = ?
			WHERE id = ?
		`, totalAmount, orderID)
		if err != nil {
			return fmt.Errorf("error updating total: %v", err)
		}

		return nil
	})

	return orderID, err
}

// BatchInsertWithTransaction batch inserts records in transaction
func BatchInsertWithTransaction(db *sql.DB, records []struct{ Name, Email string }) (int, error) {
	inserted := 0

	err := ExecuteInTransaction(db, func(tx *sql.Tx) error {
		stmt, err := tx.Prepare(`
			INSERT INTO users (username, email, password)
			VALUES (?, ?, 'default')
		`)
		if err != nil {
			return err
		}
		defer stmt.Close()

		for _, record := range records {
			_, err := stmt.Exec(record.Name, record.Email)
			if err != nil {
				log.Printf("Warning: failed to insert %s: %v
", record.Name, err)
				continue
			}
			inserted++
		}

		return nil
	})

	return inserted, err
}

// UpdateMultipleTables updates multiple tables in transaction
func UpdateMultipleTables(db *sql.DB, userID int, newEmail string) error {
	return ExecuteInTransaction(db, func(tx *sql.Tx) error {
		// Update users table
		_, err := tx.Exec(`
			UPDATE users
			SET email = ?
			WHERE id = ?
		`, newEmail, userID)
		if err != nil {
			return fmt.Errorf("error updating users: %v", err)
		}

		// Update related records
		_, err = tx.Exec(`
			UPDATE orders
			SET status = 'email_updated'
			WHERE user_id = ?
		`, userID)
		if err != nil {
			return fmt.Errorf("error updating orders: %v", err)
		}

		return nil
	})
}

// 5. Error Handling

// ExecuteWithRetry executes operation with retry on failure
func ExecuteWithRetry(db *sql.DB, maxRetries int, fn func(*sql.Tx) error) error {
	var lastErr error

	for i := 0; i < maxRetries; i++ {
		err := ExecuteInTransaction(db, fn)
		if err == nil {
			return nil
		}

		lastErr = err
		log.Printf("Attempt %d failed: %v
", i+1, err)
	}

	return fmt.Errorf("failed after %d attempts: %v", maxRetries, lastErr)
}

// ExecuteTransactionWithHandler executes with custom error handler
func ExecuteTransactionWithHandler(db *sql.DB, fn func(*sql.Tx) error, errorHandler func(error)) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	defer tx.Rollback()

	if err := fn(tx); err != nil {
		if errorHandler != nil {
			errorHandler(err)
		}
		return err
	}

	return tx.Commit()
}

// 6. Transaction Monitoring

// GetActiveTransactions returns active transaction info
func GetActiveTransactions(db *sql.DB) (map[string]interface{}, error) {
	// SQLite doesn't expose active transactions directly
	// This is a placeholder for monitoring
	info := make(map[string]interface{})

	var locked int
	err := db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'").Scan(&locked)
	if err == nil {
		info["tables"] = locked
	}

	return info, nil
}

// GetTransactionStatus checks transaction status
func GetTransactionStatus(tx *sql.Tx) (string, error) {
	// Try a simple query to check if transaction is active
	var dummy int
	err := tx.QueryRow("SELECT 1").Scan(&dummy)
	if err != nil {
		if err == sql.ErrTxDone {
			return "closed", nil
		}
		return "error", err
	}
	return "active", nil
}

// 7. Transaction Cleanup

// CleanupOldTransactions cleans up old transaction data
func CleanupOldTransactions(db *sql.DB, days int) error {
	return ExecuteInTransaction(db, func(tx *sql.Tx) error {
		_, err := tx.Exec(`
			DELETE FROM transactions
			WHERE DATE(created_at) < DATE('now', '-' || ? || ' days')
		`, days)
		if err != nil {
			return fmt.Errorf("error cleaning up: %v", err)
		}

		// Vacuum to reclaim space
		_, err = tx.Exec("VACUUM")
		return err
	})
}

// 8. Concurrent Transactions

// ExecuteConcurrentTransactions executes multiple transactions concurrently
func ExecuteConcurrentTransactions(db *sql.DB, operations []func(*sql.Tx) error) []error {
	errChan := make(chan error, len(operations))

	for _, op := range operations {
		go func(fn func(*sql.Tx) error) {
			errChan <- ExecuteInTransaction(db, fn)
		}(op)
	}

	var errors []error
	for i := 0; i < len(operations); i++ {
		if err := <-errChan; err != nil {
			errors = append(errors, err)
		}
	}

	return errors
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Transaction Handling Examples ===
")

	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Create tables
	_, err = db.Exec(`
	CREATE TABLE accounts (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		name TEXT NOT NULL,
		balance REAL NOT NULL DEFAULT 0
	)

	CREATE TABLE transactions (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		from_account INTEGER NOT NULL,
		to_account INTEGER NOT NULL,
		amount REAL NOT NULL,
		created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
		FOREIGN KEY (from_account) REFERENCES accounts(id),
		FOREIGN KEY (to_account) REFERENCES accounts(id)
	)

	CREATE TABLE products (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		name TEXT NOT NULL,
		description TEXT,
		quantity INTEGER NOT NULL DEFAULT 0,
		price REAL NOT NULL
	)

	CREATE TABLE orders (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		user_id INTEGER NOT NULL,
		total_amount REAL NOT NULL,
		status TEXT DEFAULT 'pending'
	)

	CREATE TABLE order_items (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		order_id INTEGER NOT NULL,
		product_id INTEGER NOT NULL,
		quantity INTEGER NOT NULL,
		price REAL NOT NULL,
		FOREIGN KEY (order_id) REFERENCES orders(id),
		FOREIGN KEY (product_id) REFERENCES products(id)
	)

	CREATE TABLE users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		username TEXT NOT NULL UNIQUE,
		email TEXT NOT NULL UNIQUE,
		password TEXT NOT NULL
	)
	`)
	if err != nil {
		log.Fatal(err)
	}

	// 1. Basic transaction
	fmt.Println("--- 1. Basic Transaction ---")
	_, err = db.Exec("INSERT INTO accounts (name, balance) VALUES (?, ?)", "Alice", 1000.0)
	_, err = db.Exec("INSERT INTO accounts (name, balance) VALUES (?, ?)", "Bob", 500.0)
	if err != nil {
		log.Fatal(err)
	}

	err = TransferFunds(db, 1, 2, 200.0)
	if err != nil {
		log.Printf("Transfer failed: %v
", err)
	} else {
		fmt.Println("Transfer successful")
	}

	// 2. Create order with items
	fmt.Println("
--- 2. Create Order with Items ---")
	_, err = db.Exec("INSERT INTO products (name, quantity, price) VALUES (?, ?, ?)", "Laptop", 10, 999.99)
	_, err = db.Exec("INSERT INTO products (name, quantity, price) VALUES (?, ?, ?)", "Mouse", 50, 29.99)
	_, err = db.Exec("INSERT INTO users (username, email, password) VALUES (?, ?, ?)", "john", "[email protected]", "pass")
	if err != nil {
		log.Fatal(err)
	}

	items := []struct{ ProductID, Quantity int; Price float64 }{
		{1, 1, 999.99},
		{2, 2, 29.99},
	}
	orderID, err := CreateOrderWithItems(db, 1, items)
	if err != nil {
		log.Printf("Order creation failed: %v
", err)
	} else {
		fmt.Printf("Order created with ID: %d
", orderID)
	}

	// 3. Batch insert
	fmt.Println("
--- 3. Batch Insert ---")
	users := []struct{ Name, Email string }{
		{"user1", "[email protected]"},
		{"user2", "[email protected]"},
		{"user3", "[email protected]"},
	}
	inserted, err := BatchInsertWithTransaction(db, users)
	if err == nil {
		fmt.Printf("Inserted %d users
", inserted)
	}

	// 4. Error handling
	fmt.Println("
--- 4. Transaction with Error Handling ---")
	err = ExecuteWithRetry(db, 3, func(tx *sql.Tx) error {
		// Simulate operation
		_, err := tx.Exec("INSERT INTO accounts (name, balance) VALUES (?, ?)", "Charlie", 100.0)
		return err
	})
	if err != nil {
		log.Printf("Operation failed: %v
", err)
	} else {
		fmt.Println("Operation successful")
	}

	// 5. Update multiple tables
	fmt.Println("
--- 5. Update Multiple Tables ---")
	err = UpdateMultipleTables(db, 1, "[email protected]")
	if err != nil {
		log.Printf("Update failed: %v
", err)
	} else {
		fmt.Println("Multiple tables updated")
	}

	fmt.Println("
=== All Transaction Handling Examples Completed ===")
}

💻 Conexão SQLite go

🟡 intermediate ⭐⭐⭐

Conectar ao banco de dados SQLite, criar tabelas e gerenciar conexões de banco de dados usando o pacote database/sql do Go

⏱️ 30 min 🏷️ go, web, database, sqlite
Prerequisites: Intermediate Go, database/sql package, SQLite
// Web Go SQLite Connection Examples
// Database connectivity and management with SQLite

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	_ "github.com/mattn/go-sqlite3" // SQLite driver
)

// 1. Basic Connection

// OpenDatabase opens SQLite database connection
func OpenDatabase(dbPath string) (*sql.DB, error) {
	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return nil, fmt.Errorf("error opening database: %v", err)
	}

	// Test connection
	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("error connecting to database: %v", err)
	}

	return db, nil
}

// OpenDatabaseWithTimeout opens database with timeout
func OpenDatabaseWithTimeout(dbPath string, timeout time.Duration) (*sql.DB, error) {
	db, err := sql.Open("sqlite3", dbPath+"?_timeout="+timeout.String())
	if err != nil {
		return nil, fmt.Errorf("error opening database: %v", err)
	}

	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("error connecting to database: %v", err)
	}

	return db, nil
}

// OpenInMemoryDatabase opens in-memory SQLite database
func OpenInMemoryDatabase() (*sql.DB, error) {
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		return nil, fmt.Errorf("error opening in-memory database: %v", err)
	}

	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("error connecting to database: %v", err)
	}

	return db, nil
}

// CloseDatabase closes database connection properly
func CloseDatabase(db *sql.DB) error {
	return db.Close()
}

// 2. Connection Management

// ConfigureConnectionPool configures connection pool settings
func ConfigureConnectionPool(db *sql.DB, maxOpen, maxIdle int, maxLifetime time.Duration) {
	db.SetMaxOpenConns(maxOpen)
	db.SetMaxIdleConns(maxIdle)
	db.SetConnMaxLifetime(maxLifetime)
}

// GetConnectionStats returns connection pool statistics
func GetConnectionStats(db *sql.DB) map[string]interface{} {
	stats := db.Stats()
	return map[string]interface{}{
		"max_open_connections": stats.MaxOpenConnections,
		"open_connections":     stats.OpenConnections,
		"in_use":               stats.InUse,
		"idle":                 stats.Idle,
		"wait_count":           stats.WaitCount,
		"wait_duration":        stats.WaitDuration.String(),
		"max_idle_closed":      stats.MaxIdleClosed,
		"max_lifetime_closed":  stats.MaxLifetimeClosed,
	}
}

// TestConnection tests database connection
func TestConnection(db *sql.DB) error {
	return db.Ping()
}

// 3. Table Creation

// CreateUsersTable creates users table
func CreateUsersTable(db *sql.DB) error {
	query := `
	CREATE TABLE IF NOT EXISTS users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		username TEXT NOT NULL UNIQUE,
		email TEXT NOT NULL UNIQUE,
		password TEXT NOT NULL,
		full_name TEXT,
		created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
		updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
	)
	`

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating users table: %v", err)
	}

	return nil
}

// CreateProductsTable creates products table
func CreateProductsTable(db *sql.DB) error {
	query := `
	CREATE TABLE IF NOT EXISTS products (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		name TEXT NOT NULL,
		description TEXT,
		price REAL NOT NULL,
		quantity INTEGER DEFAULT 0,
		category TEXT,
		created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
		updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
	)
	`

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating products table: %v", err)
	}

	return nil
}

// CreateOrdersTable creates orders table with foreign key
func CreateOrdersTable(db *sql.DB) error {
	query := `
	CREATE TABLE IF NOT EXISTS orders (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		user_id INTEGER NOT NULL,
		total_amount REAL NOT NULL,
		status TEXT DEFAULT 'pending',
		created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
		FOREIGN KEY (user_id) REFERENCES users(id)
	)
	`

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating orders table: %v", err)
	}

	return nil
}

// CreateOrderItemsTable creates order_items table with many-to-many relationship
func CreateOrderItemsTable(db *sql.DB) error {
	query := `
	CREATE TABLE IF NOT EXISTS order_items (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		order_id INTEGER NOT NULL,
		product_id INTEGER NOT NULL,
		quantity INTEGER NOT NULL,
		price REAL NOT NULL,
		FOREIGN KEY (order_id) REFERENCES orders(id),
		FOREIGN KEY (product_id) REFERENCES products(id)
	)
	`

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating order_items table: %v", err)
	}

	return nil
}

// 4. Index Management

// CreateIndex creates an index on table
func CreateIndex(db *sql.DB, indexName, tableName, columns string) error {
	query := fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s(%s)",
		indexName, tableName, columns)

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating index: %v", err)
	}

	return nil
}

// CreateUniqueIndex creates unique index
func CreateUniqueIndex(db *sql.DB, indexName, tableName, columns string) error {
	query := fmt.Sprintf("CREATE UNIQUE INDEX IF NOT EXISTS %s ON %s(%s)",
		indexName, tableName, columns)

	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating unique index: %v", err)
	}

	return nil
}

// DropIndex removes an index
func DropIndex(db *sql.DB, indexName string) error {
	query := fmt.Sprintf("DROP INDEX IF EXISTS %s", indexName)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error dropping index: %v", err)
	}

	return nil
}

// ListIndexes lists all indexes
func ListIndexes(db *sql.DB) ([]string, error) {
	query := "SELECT name FROM sqlite_master WHERE type = 'index'"
	rows, err := db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var indexes []string
	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			continue
		}
		indexes = append(indexes, name)
	}

	return indexes, nil
}

// 5. Schema Management

// GetTableSchema retrieves table schema
func GetTableSchema(db *sql.DB, tableName string) ([]map[string]interface{}, error) {
	query := fmt.Sprintf("PRAGMA table_info(%s)", tableName)
	rows, err := db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var schema []map[string]interface{}
	for rows.Next() {
		var cid int
		var name, datatype string
		var notnull, pk int
		var dfltValue interface{}

		err := rows.Scan(&cid, &name, &datatype, &notnull, &dfltValue, &pk)
		if err != nil {
			continue
		}

		schema = append(schema, map[string]interface{}{
			"cid":        cid,
			"name":       name,
			"datatype":   datatype,
			"notnull":    notnull == 1,
			"dflt_value": dfltValue,
			"pk":         pk == 1,
		})
	}

	return schema, nil
}

// ListTables lists all tables in database
func ListTables(db *sql.DB) ([]string, error) {
	query := "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'"
	rows, err := db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var tables []string
	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			continue
		}
		tables = append(tables, name)
	}

	return tables, nil
}

// TableExists checks if table exists
func TableExists(db *sql.DB, tableName string) bool {
	query := "SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?"
	var name string
	err := db.QueryRow(query, tableName).Scan(&name)
	return err == nil
}

// 6. Database Information

// GetDatabaseVersion returns SQLite version
func GetDatabaseVersion(db *sql.DB) (string, error) {
	var version string
	err := db.QueryRow("SELECT sqlite_version()").Scan(&version)
	if err != nil {
		return "", err
	}
	return version, nil
}

// GetDatabaseSize returns database file size
func GetDatabaseSize(db *sql.DB) (int64, error) {
	var size int64
	var pageCount, pageSize int

	err := db.QueryRow("PRAGMA page_count").Scan(&pageCount)
	if err != nil {
		return 0, err
	}

	err = db.QueryRow("PRAGMA page_size").Scan(&pageSize)
	if err != nil {
		return 0, err
	}

	size = int64(pageCount) * int64(pageSize)
	return size, nil
}

// GetDatabaseInfo returns database information
func GetDatabaseInfo(db *sql.DB) (map[string]interface{}, error) {
	info := make(map[string]interface{})

	// Get version
	version, err := GetDatabaseVersion(db)
	if err == nil {
		info["version"] = version
	}

	// Get size
	size, err := GetDatabaseSize(db)
	if err == nil {
		info["size_bytes"] = size
	}

	// Get tables
	tables, err := ListTables(db)
	if err == nil {
		info["tables"] = tables
		info["table_count"] = len(tables)
	}

	// Get connection stats
	stats := GetConnectionStats(db)
	info["connection_stats"] = stats

	return info, nil
}

// 7. Backup and Restore

// BackupDatabase creates database backup
func BackupDatabase(db *sql.DB, backupPath string) error {
	query := fmt.Sprintf("VACUUM INTO '%s'", backupPath)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error creating backup: %v", err)
	}
	return nil
}

// OptimizeDatabase optimizes database
func OptimizeDatabase(db *sql.DB) error {
	_, err := db.Exec("VACUUM")
	if err != nil {
		return fmt.Errorf("error vacuuming database: %v", err)
	}

	_, err = db.Exec("ANALYZE")
	if err != nil {
		return fmt.Errorf("error analyzing database: %v", err)
	}

	return nil
}

// 8. Database Maintenance

// EnableForeignKeys enables foreign key constraints
func EnableForeignKeys(db *sql.DB) error {
	_, err := db.Exec("PRAGMA foreign_keys = ON")
	if err != nil {
		return fmt.Errorf("error enabling foreign keys: %v", err)
	}
	return nil
}

// EnableWALMode enables Write-Ahead Logging mode
func EnableWALMode(db *sql.DB) error {
	_, err := db.Exec("PRAGMA journal_mode = WAL")
	if err != nil {
		return fmt.Errorf("error enabling WAL mode: %v", err)
	}
	return nil
}

// SetSynchronousMode sets synchronous mode
func SetSynchronousMode(db *sql.DB, mode string) error {
	query := fmt.Sprintf("PRAGMA synchronous = %s", mode)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error setting synchronous mode: %v", err)
	}
	return nil
}

// SetCacheSize sets cache size
func SetCacheSize(db *sql.DB, size int) error {
	query := fmt.Sprintf("PRAGMA cache_size = -%d", size)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error setting cache size: %v", err)
	}
	return nil
}

// 9. Database Operations

// DropTable drops a table
func DropTable(db *sql.DB, tableName string) error {
	query := fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error dropping table: %v", err)
	}
	return nil
}

// TruncateTable removes all rows from table
func TruncateTable(db *sql.DB, tableName string) error {
	query := fmt.Sprintf("DELETE FROM %s", tableName)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error truncating table: %v", err)
	}

	// Reset autoincrement
	_, err = db.Exec(fmt.Sprintf("DELETE FROM sqlite_sequence WHERE name='%s'", tableName))
	if err != nil {
		return fmt.Errorf("error resetting sequence: %v", err)
	}

	return nil
}

// RenameTable renames a table
func RenameTable(db *sql.DB, oldName, newName string) error {
	query := fmt.Sprintf("ALTER TABLE %s RENAME TO %s", oldName, newName)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error renaming table: %v", err)
	}
	return nil
}

// AddColumn adds column to table
func AddColumn(db *sql.DB, tableName, columnName, columnDef string) error {
	query := fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s", tableName, columnName, columnDef)
	_, err := db.Exec(query)
	if err != nil {
		return fmt.Errorf("error adding column: %v", err)
	}
	return nil
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go SQLite Connection Examples ===
")

	// 1. Open database
	fmt.Println("--- 1. Open Database ---")
	db, err := OpenDatabase("test.db")
	if err != nil {
		log.Fatal(err)
	}
	defer CloseDatabase(db)
	fmt.Println("Database opened successfully")

	// 2. Configure connection pool
	fmt.Println("
--- 2. Configure Connection Pool ---")
	ConfigureConnectionPool(db, 10, 5, time.Hour)
	stats := GetConnectionStats(db)
	fmt.Printf("Connection stats: %+v
", stats)

	// 3. Create tables
	fmt.Println("
--- 3. Create Tables ---")
	if err := CreateUsersTable(db); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Users table created")

	if err := CreateProductsTable(db); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Products table created")

	// 4. Create indexes
	fmt.Println("
--- 4. Create Indexes ---")
	if err := CreateIndex(db, "idx_users_email", "users", "email"); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Index created")

	// 5. List tables
	fmt.Println("
--- 5. List Tables ---")
	tables, err := ListTables(db)
	if err == nil {
		fmt.Printf("Tables: %v
", tables)
	}

	// 6. Get table schema
	fmt.Println("
--- 6. Table Schema ---")
	schema, err := GetTableSchema(db, "users")
	if err == nil {
		for _, col := range schema {
			fmt.Printf("Column: %+v
", col)
		}
	}

	// 7. Database info
	fmt.Println("
--- 7. Database Info ---")
	info, err := GetDatabaseInfo(db)
	if err == nil {
		fmt.Printf("Database info: %+v
", info)
	}

	// 8. Enable foreign keys
	fmt.Println("
--- 8. Enable Foreign Keys ---")
	if err := EnableForeignKeys(db); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Foreign keys enabled")

	// 9. Optimize database
	fmt.Println("
--- 9. Optimize Database ---")
	if err := OptimizeDatabase(db); err != nil {
		log.Printf("Warning: %v", err)
	} else {
		fmt.Println("Database optimized")
	}

	fmt.Println("
=== All SQLite Connection Examples Completed ===")
}

💻 Execução de Consultas SQL go

🟡 intermediate ⭐⭐⭐⭐

Executar consultas SELECT, INSERT, UPDATE, DELETE com vinculação de parâmetros e processamento de resultados

⏱️ 35 min 🏷️ go, web, database, sql, crud
Prerequisites: Intermediate Go, database/sql package, SQL knowledge
// Web Go SQL Query Execution Examples
// CRUD operations with parameterized queries

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// 1. INSERT Operations

// InsertUser inserts a new user
func InsertUser(db *sql.DB, username, email, password, fullName string) (int64, error) {
	query := `
	INSERT INTO users (username, email, password, full_name)
	VALUES (?, ?, ?, ?)
	`

	result, err := db.Exec(query, username, email, password, fullName)
	if err != nil {
		return 0, fmt.Errorf("error inserting user: %v", err)
	}

	id, err := result.LastInsertId()
	if err != nil {
		return 0, fmt.Errorf("error getting last insert id: %v", err)
	}

	return id, nil
}

// InsertUserWithTimestamp inserts user with custom timestamp
func InsertUserWithTimestamp(db *sql.DB, username, email, password, fullName string, createdAt time.Time) (int64, error) {
	query := `
	INSERT INTO users (username, email, password, full_name, created_at)
	VALUES (?, ?, ?, ?, ?)
	`

	result, err := db.Exec(query, username, email, password, fullName, createdAt)
	if err != nil {
		return 0, fmt.Errorf("error inserting user: %v", err)
	}

	return result.LastInsertId()
}

// BatchInsertUsers inserts multiple users efficiently
func BatchInsertUsers(db *sql.DB, users []struct{ Username, Email, Password, FullName string }) error {
	tx, err := db.Begin()
	if err != nil {
		return fmt.Errorf("error beginning transaction: %v", err)
	}
	defer tx.Rollback()

	stmt, err := tx.Prepare(`
		INSERT INTO users (username, email, password, full_name)
		VALUES (?, ?, ?, ?)
	`)
	if err != nil {
		return fmt.Errorf("error preparing statement: %v", err)
	}
	defer stmt.Close()

	for _, user := range users {
		_, err := stmt.Exec(user.Username, user.Email, user.Password, user.FullName)
		if err != nil {
			return fmt.Errorf("error inserting user: %v", err)
		}
	}

	return tx.Commit()
}

// InsertOrUpdateUser inserts or updates user (UPSERT)
func InsertOrUpdateUser(db *sql.DB, username, email, fullName string) error {
	query := `
	INSERT INTO users (username, email, full_name)
	VALUES (?, ?, ?)
	ON CONFLICT(username) DO UPDATE SET
		email = excluded.email,
		full_name = excluded.full_name,
		updated_at = CURRENT_TIMESTAMP
	`

	_, err := db.Exec(query, username, email, fullName)
	if err != nil {
		return fmt.Errorf("error upserting user: %v", err)
	}

	return nil
}

// 2. SELECT Operations

// GetUserByID retrieves user by ID
func GetUserByID(db *sql.DB, userID int) (map[string]interface{}, error) {
	query := `
	SELECT id, username, email, full_name, created_at, updated_at
	FROM users
	WHERE id = ?
	`

	var id int
	var username, email, fullName, createdAt, updatedAt string

	err := db.QueryRow(query, userID).Scan(
		&id, &username, &email, &fullName, &createdAt, &updatedAt,
	)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, fmt.Errorf("user not found")
		}
		return nil, fmt.Errorf("error querying user: %v", err)
	}

	return map[string]interface{}{
		"id":         id,
		"username":   username,
		"email":      email,
		"full_name":  fullName,
		"created_at": createdAt,
		"updated_at": updatedAt,
	}, nil
}

// GetUserByUsername retrieves user by username
func GetUserByUsername(db *sql.DB, username string) (map[string]interface{}, error) {
	query := `
	SELECT id, username, email, full_name, created_at
	FROM users
	WHERE username = ?
	`

	var id int
	var user, email, fullName, createdAt string

	err := db.QueryRow(query, username).Scan(
		&id, &user, &email, &fullName, &createdAt,
	)
	if err != nil {
		return nil, err
	}

	return map[string]interface{}{
		"id":         id,
		"username":   user,
		"email":      email,
		"full_name":  fullName,
		"created_at": createdAt,
	}, nil
}

// GetAllUsers retrieves all users
func GetAllUsers(db *sql.DB) ([]map[string]interface{}, error) {
	query := `
	SELECT id, username, email, full_name, created_at
	FROM users
	ORDER BY created_at DESC
	`

	rows, err := db.Query(query)
	if err != nil {
		return nil, fmt.Errorf("error querying users: %v", err)
	}
	defer rows.Close()

	var users []map[string]interface{}
	for rows.Next() {
		var id int
		var username, email, fullName, createdAt string

		err := rows.Scan(&id, &username, &email, &fullName, &createdAt)
		if err != nil {
			continue
		}

		users = append(users, map[string]interface{}{
			"id":         id,
			"username":   username,
			"email":      email,
			"full_name":  fullName,
			"created_at": createdAt,
		})
	}

	return users, nil
}

// GetUsersWithPagination retrieves users with pagination
func GetUsersWithPagination(db *sql.DB, limit, offset int) ([]map[string]interface{}, int, error) {
	// Get total count
	var total int
	err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&total)
	if err != nil {
		return nil, 0, err
	}

	// Get paginated results
	query := `
	SELECT id, username, email, full_name
	FROM users
	ORDER BY created_at DESC
	LIMIT ? OFFSET ?
	`

	rows, err := db.Query(query, limit, offset)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	var users []map[string]interface{}
	for rows.Next() {
		var id int
		var username, email, fullName string

		err := rows.Scan(&id, &username, &email, &fullName)
		if err != nil {
			continue
		}

		users = append(users, map[string]interface{}{
			"id":        id,
			"username":  username,
			"email":     email,
			"full_name": fullName,
		})
	}

	return users, total, nil
}

// SearchUsersByUsername searches users by username pattern
func SearchUsersByUsername(db *sql.DB, pattern string) ([]map[string]interface{}, error) {
	query := `
	SELECT id, username, email, full_name
	FROM users
	WHERE username LIKE ?
	ORDER BY username
	`

	rows, err := db.Query(query, "%"+pattern+"%")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var users []map[string]interface{}
	for rows.Next() {
		var id int
		var username, email, fullName string

		err := rows.Scan(&id, &username, &email, &fullName)
		if err != nil {
			continue
		}

		users = append(users, map[string]interface{}{
			"id":        id,
			"username":  username,
			"email":     email,
			"full_name": fullName,
		})
	}

	return users, nil
}

// 3. UPDATE Operations

// UpdateUser updates user information
func UpdateUser(db *sql.DB, userID int, email, fullName string) error {
	query := `
	UPDATE users
	SET email = ?, full_name = ?, updated_at = CURRENT_TIMESTAMP
	WHERE id = ?
	`

	result, err := db.Exec(query, email, fullName, userID)
	if err != nil {
		return fmt.Errorf("error updating user: %v", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rowsAffected == 0 {
		return fmt.Errorf("no user found with id %d", userID)
	}

	return nil
}

// UpdateUserPassword updates user password
func UpdateUserPassword(db *sql.DB, userID int, newPassword string) error {
	query := `
	UPDATE users
	SET password = ?, updated_at = CURRENT_TIMESTAMP
	WHERE id = ?
	`

	result, err := db.Exec(query, newPassword, userID)
	if err != nil {
		return fmt.Errorf("error updating password: %v", err)
	}

	rowsAffected, _ := result.RowsAffected()
	if rowsAffected == 0 {
		return fmt.Errorf("user not found")
	}

	return nil
}

// IncrementFieldValue increments a numeric field
func IncrementFieldValue(db *sql.DB, table, column string, id int) error {
	query := fmt.Sprintf(`
	UPDATE %s
	SET %s = %s + 1
	WHERE id = ?
	`, table, column, column)

	result, err := db.Exec(query, id)
	if err != nil {
		return err
	}

	rowsAffected, _ := result.RowsAffected()
	if rowsAffected == 0 {
		return fmt.Errorf("record not found")
	}

	return nil
}

// 4. DELETE Operations

// DeleteUser deletes user by ID
func DeleteUser(db *sql.DB, userID int) error {
	query := "DELETE FROM users WHERE id = ?"

	result, err := db.Exec(query, userID)
	if err != nil {
		return fmt.Errorf("error deleting user: %v", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rowsAffected == 0 {
		return fmt.Errorf("no user found with id %d", userID)
	}

	return nil
}

// DeleteUsersByCondition deletes users matching condition
func DeleteUsersByCondition(db *sql.DB, condition string, args ...interface{}) (int64, error) {
	query := "DELETE FROM users WHERE " + condition

	result, err := db.Exec(query, args...)
	if err != nil {
		return 0, fmt.Errorf("error deleting users: %v", err)
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return rowsAffected, nil
}

// DeleteAllUsers deletes all users (use with caution)
func DeleteAllUsers(db *sql.DB) error {
	_, err := db.Exec("DELETE FROM users")
	if err != nil {
		return fmt.Errorf("error deleting all users: %v", err)
	}

	// Reset autoincrement
	_, err = db.Exec("DELETE FROM sqlite_sequence WHERE name='users'")
	return err
}

// 5. Complex Queries

// GetUsersWithOrders retrieves users with their order count
func GetUsersWithOrders(db *sql.DB) ([]map[string]interface{}, error) {
	query := `
	SELECT
		u.id,
		u.username,
		u.email,
		COUNT(o.id) as order_count,
		COALESCE(SUM(o.total_amount), 0) as total_spent
	FROM users u
	LEFT JOIN orders o ON u.id = o.user_id
	GROUP BY u.id
	ORDER BY total_spent DESC
	`

	rows, err := db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var results []map[string]interface{}
	for rows.Next() {
		var id, orderCount int
		var username, email string
		var totalSpent float64

		err := rows.Scan(&id, &username, &email, &orderCount, &totalSpent)
		if err != nil {
			continue
		}

		results = append(results, map[string]interface{}{
			"id":           id,
			"username":     username,
			"email":        email,
			"order_count":  orderCount,
			"total_spent":  totalSpent,
		})
	}

	return results, nil
}

// GetTopCustomers retrieves top customers by spending
func GetTopCustomers(db *sql.DB, limit int) ([]map[string]interface{}, error) {
	query := `
	SELECT
		u.id,
		u.username,
		u.email,
		COUNT(o.id) as order_count,
		COALESCE(SUM(o.total_amount), 0) as total_spent
	FROM users u
	INNER JOIN orders o ON u.id = o.user_id
	GROUP BY u.id
	ORDER BY total_spent DESC
	LIMIT ?
	`

	rows, err := db.Query(query, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var customers []map[string]interface{}
	for rows.Next() {
		var id, orderCount int
		var username, email string
		var totalSpent float64

		err := rows.Scan(&id, &username, &email, &orderCount, &totalSpent)
		if err != nil {
			continue
		}

		customers = append(customers, map[string]interface{}{
			"id":          id,
			"username":    username,
			"email":       email,
			"order_count": orderCount,
			"total_spent": totalSpent,
		})
	}

	return customers, nil
}

// 6. Aggregate Functions

// GetUserStatistics returns user statistics
func GetUserStatistics(db *sql.DB) (map[string]interface{}, error) {
	stats := make(map[string]interface{})

	// Total users
	var totalUsers int
	db.QueryRow("SELECT COUNT(*) FROM users").Scan(&totalUsers)
	stats["total_users"] = totalUsers

	// Users created today
	var usersToday int
	db.QueryRow("SELECT COUNT(*) FROM users WHERE DATE(created_at) = DATE('now')").Scan(&usersToday)
	stats["users_today"] = usersToday

	// Users created this week
	var usersWeek int
	db.QueryRow("SELECT COUNT(*) FROM users WHERE created_at >= DATE('now', '-7 days')").Scan(&usersWeek)
	stats["users_this_week"] = usersWeek

	// Users created this month
	var usersMonth int
	db.QueryRow("SELECT COUNT(*) FROM users WHERE created_at >= DATE('now', 'start of month')").Scan(&usersMonth)
	stats["users_this_month"] = usersMonth

	return stats, nil
}

// GetColumnStatistics returns statistics for numeric column
func GetColumnStatistics(db *sql.DB, table, column string) (map[string]interface{}, error) {
	query := fmt.Sprintf(`
	SELECT
		COUNT(*) as count,
		COALESCE(AVG(%s), 0) as average,
		COALESCE(MIN(%s), 0) as minimum,
		COALESCE(MAX(%s), 0) as maximum,
		COALESCE(SUM(%s), 0) as total
	FROM %s
	`, column, column, column, column, table)

	var count int
	var average, minimum, maximum, total float64

	err := db.QueryRow(query).Scan(&count, &average, &minimum, &maximum, &total)
	if err != nil {
		return nil, err
	}

	return map[string]interface{}{
		"count":   count,
		"average": average,
		"minimum": minimum,
		"maximum": maximum,
		"total":   total,
	}, nil
}

// 7. Prepared Statements

// CreatePreparedStatement creates and returns prepared statement
func CreatePreparedStatement(db *sql.DB, query string) (*sql.Stmt, error) {
	return db.Prepare(query)
}

// ExecutePreparedStatement executes prepared statement
func ExecutePreparedStatement(stmt *sql.Stmt, args ...interface{}) (sql.Result, error) {
	return stmt.Exec(args...)
}

// QueryPreparedStatement queries with prepared statement
func QueryPreparedStatement(stmt *sql.Stmt, args ...interface{}) (*sql.Rows, error) {
	return stmt.Query(args...)
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go SQL Query Execution Examples ===
")

	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Create table
	_, err = db.Exec(`
	CREATE TABLE users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		username TEXT NOT NULL UNIQUE,
		email TEXT NOT NULL UNIQUE,
		password TEXT NOT NULL,
		full_name TEXT,
		created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
		updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
	)
	`)
	if err != nil {
		log.Fatal(err)
	}

	// 1. INSERT
	fmt.Println("--- 1. Insert Users ---")
	id, err := InsertUser(db, "john_doe", "[email protected]", "hashed_password", "John Doe")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Inserted user with ID: %d
", id)

	InsertUser(db, "jane_smith", "[email protected]", "hashed_password", "Jane Smith")
	InsertUser(db, "bob_wilson", "[email protected]", "hashed_password", "Bob Wilson")

	// 2. SELECT
	fmt.Println("
--- 2. Query Users ---")
	user, err := GetUserByID(db, 1)
	if err == nil {
		fmt.Printf("User: %+v
", user)
	}

	users, err := GetAllUsers(db)
	if err == nil {
		fmt.Printf("Total users: %d
", len(users))
	}

	// 3. SEARCH
	fmt.Println("
--- 3. Search Users ---")
	results, err := SearchUsersByUsername(db, "john")
	if err == nil {
		fmt.Printf("Found %d users
", len(results))
	}

	// 4. UPDATE
	fmt.Println("
--- 4. Update User ---")
	err = UpdateUser(db, 1, "[email protected]", "John Doe Jr.")
	if err == nil {
		fmt.Println("User updated successfully")
	}

	// 5. STATISTICS
	fmt.Println("
--- 5. Statistics ---")
	stats, err := GetUserStatistics(db)
	if err == nil {
		fmt.Printf("Statistics: %+v
", stats)
	}

	// 6. DELETE
	fmt.Println("
--- 6. Delete User ---")
	err = DeleteUser(db, 2)
	if err == nil {
		fmt.Println("User deleted successfully")
	}

	// 7. BATCH
	fmt.Println("
--- 7. Batch Insert ---")
	newUsers := []struct{ Username, Email, Password, FullName string }{
		{"user1", "[email protected]", "pass", "User 1"},
		{"user2", "[email protected]", "pass", "User 2"},
		{"user3", "[email protected]", "pass", "User 3"},
	}
	err = BatchInsertUsers(db, newUsers)
	if err == nil {
		fmt.Println("Batch insert successful")
	}

	fmt.Println("
=== All SQL Query Execution Examples Completed ===")
}