sqlite使用

Posted by     "zengchengjie" on Friday, January 28, 2022

SQLite 使用指南:从入门到实践

引言

在移动互联网时代,本地数据存储是每个开发者都必须面对的问题。无论是手机应用、桌面软件,还是物联网设备,如何高效、可靠地存储和管理数据,始终是一个核心需求。

SQLite 给出了一个优雅的答案——一个零配置、无服务器、嵌入式的关系型数据库引擎。它不需要安装,不需要配置,不需要启动独立的服务进程,整个数据库就是一个普通的磁盘文件。正因如此,SQLite 成为了全球部署最广泛的数据库引擎,从 Android 到 iOS,从浏览器到桌面应用,处处都有它的身影。

本文将带你从零开始,全面掌握 SQLite 的使用——从命令行工具到编程语言集成,从基础 CRUD 到性能优化,最后通过一个完整的实战项目串联所有知识点。

一、SQLite 是什么?

1.1 核心特性

SQLite 的设计理念可以用四个字概括:轻量、可靠

特性 说明
零配置 无需安装、无需配置、无需启动服务进程
无服务器 应用程序直接读写磁盘文件,无中间件开销
单文件存储 整个数据库(表、索引、视图)存储在一个文件中
跨平台 支持 Windows、Linux、macOS、iOS、Android 等全平台
ACID 兼容 支持事务、原子性、一致性、隔离性、持久性
轻量级 核心库仅约 500KB,内存占用极低
公有领域 完全免费,可用于任何商业用途

1.2 适用场景

SQLite 的“轻量”并不等于“弱鸡”。它的适用场景非常广泛:

  • 移动应用本地存储:Android 和 iOS 的首选嵌入式数据库
  • 桌面软件配置管理:浏览器书签、IDE 配置、邮件客户端
  • 物联网设备数据采集:传感器数据的本地缓存与同步
  • 开发与测试环境:原型验证、单元测试的临时数据库
  • 中小型网站后端:访问量不大的 Web 应用

当然,SQLite 也有它的边界——超高并发写入、客户端-服务器架构、细粒度用户权限管理等场景,更适合使用 PostgreSQL 或 MySQL。

1.3 命令行工具 vs SQLite 库

这里需要区分两个容易混淆的概念:

  • SQLite 库(library):实现 SQL 数据库引擎的代码,是供其他程序调用的底层组件
  • sqlite3 命令行工具(CLI):一个独立的应用程序,为用户提供手动输入和执行 SQL 的界面

当我们说“学习 SQLite”时,通常是指学习如何使用 SQLite 库;而 sqlite3 命令行工具是我们学习和调试的得力助手。

二、快速开始:命令行工具的使用

无论你最终用哪种编程语言操作 SQLite,掌握 sqlite3 命令行工具都是非常有帮助的——它可以让你快速验证 SQL 语句、查看数据库结构、进行数据导入导出。

2.1 安装

Windows:下载预编译的二进制包(sqlite-tools-win32-*.zip),解压后将 sqlite3.exe 所在目录添加到系统 PATH

Linux

sudo apt install sqlite3
# 或
sudo yum install sqlite3

macOS

brew install sqlite3

2.2 启动并创建数据库

启动 sqlite3 时,可以指定数据库文件名。如果文件不存在,SQLite 会自动创建:

$ sqlite3 test.db
SQLite version 3.43.0 2023-08-11 17:45:23
Enter ".help" for usage hints.
sqlite>

如果不指定数据库文件名,SQLite 会使用一个临时内存数据库,程序退出后数据即消失:

$ sqlite3
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>

2.3 基本操作

-- 创建表
sqlite> CREATE TABLE users (
   ...>   id INTEGER PRIMARY KEY AUTOINCREMENT,
   ...>   name TEXT NOT NULL,
   ...>   age INTEGER,
   ...>   created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
   ...> );

-- 插入数据
sqlite> INSERT INTO users (name, age) VALUES ('Alice', 25);
sqlite> INSERT INTO users (name, age) VALUES ('Bob', 30);
sqlite> INSERT INTO users (name, age) VALUES ('Charlie', 28);

-- 查询数据
sqlite> SELECT * FROM users;
1|Alice|25|2025-01-15 10:30:00
2|Bob|30|2025-01-15 10:30:05
3|Charlie|28|2025-01-15 10:30:10

-- 设置输出格式(更易读)
sqlite> .mode column
sqlite> .headers on
sqlite> SELECT * FROM users;
id  name      age  created_at
--  --------  ---  -------------------
1   Alice     25   2025-01-15 10:30:00
2   Bob       30   2025-01-15 10:30:05
3   Charlie   28   2025-01-15 10:30:10

2.4 常用点命令

sqlite3 有一类以点(.)开头的特殊命令,称为点命令(dot-command),用于控制输出格式和执行管理操作:

命令 作用
.tables 列出当前数据库中的所有表
.schema [表名] 显示表的创建语句
.databases 显示当前打开的数据库文件
.mode [模式] 设置查询结果的输出格式(column、csv、json 等)
.headers on/off 是否显示列名
.output [文件名] 将输出重定向到文件
.import [文件] [表名] 从 CSV 文件导入数据
.dump 将整个数据库导出为 SQL 语句
.quit 退出命令行工具

查看所有可用命令:

sqlite> .help

2.5 退出命令行

输入系统 EOF 字符(通常是 Ctrl+D)或执行 .quit 命令:

sqlite> .quit

三、核心 SQL 操作

SQLite 支持标准的 SQL 语法,以下是最常用的操作。

3.1 创建表

-- 基础表结构
CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    price REAL CHECK(price > 0),
    stock INTEGER DEFAULT 0,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 添加索引(提升查询性能)
CREATE INDEX idx_products_name ON products(name);
CREATE INDEX idx_products_price ON products(price);

-- 复合索引
CREATE INDEX idx_products_name_price ON products(name, price);

字段类型说明:SQLite 是动态类型数据库,但推荐使用以下类型:

  • INTEGER:整数
  • REAL:浮点数
  • TEXT:文本字符串
  • BLOB:二进制数据

3.2 插入数据

-- 单条插入
INSERT INTO products (name, price, stock) VALUES ('Laptop', 5999.00, 10);

-- 批量插入
INSERT INTO products (name, price, stock) VALUES 
    ('Mouse', 29.90, 100),
    ('Keyboard', 89.90, 50),
    ('Monitor', 1299.00, 20);

-- 插入或替换(主键冲突时替换)
INSERT OR REPLACE INTO products (id, name, price) VALUES (1, 'Gaming Laptop', 7999.00);

3.3 查询数据

-- 基础查询
SELECT * FROM products WHERE price > 100;

-- 分页查询(推荐方式:基于 ID)
SELECT * FROM products WHERE id > last_id ORDER BY id LIMIT 10;

-- 传统分页(偏移量大时性能较差)
SELECT * FROM products LIMIT 10 OFFSET 1000;

-- 聚合查询
SELECT 
    COUNT(*) as total,
    AVG(price) as avg_price,
    MAX(price) as max_price,
    SUM(stock) as total_stock
FROM products;

3.4 更新与删除

-- 更新数据
UPDATE products SET price = 6499.00 WHERE name = 'Laptop';

-- 删除数据
DELETE FROM products WHERE stock = 0;

-- 清空表(重置 AUTOINCREMENT)
DELETE FROM products;
-- 或
DROP TABLE products;

3.5 事务处理

事务可以保证一组操作要么全部成功,要么全部失败,常用于批量操作和数据一致性场景:

BEGIN TRANSACTION;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    
    -- 检查结果
    SELECT * FROM accounts;
COMMIT;  -- 提交事务

-- 如果出错,可以回滚
ROLLBACK;

四、编程语言集成:Go + SQLite 实战

理论讲完,我们来写点实际的代码。这里以 Go 语言为例,演示如何用 SQLite 构建一个完整的应用。

4.1 安装驱动

Go 中最常用的 SQLite 驱动是 mattn/go-sqlite3

go get github.com/mattn/go-sqlite3

4.2 数据库连接与初始化

package main

import (
    "database/sql"
    "log"
    
    _ "github.com/mattn/go-sqlite3"  // 匿名导入,仅执行 init 函数
)

var db *sql.DB

func initDB() {
    var err error
    // 打开数据库文件(不存在则自动创建)
    db, err = sql.Open("sqlite3", "./app.db")
    if err != nil {
        log.Fatal(err)
    }
    
    // 测试连接
    if err = db.Ping(); err != nil {
        log.Fatal(err)
    }
    
    // 创建表
    createTableSQL := `
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        email TEXT NOT NULL,
        age INTEGER DEFAULT 0,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );`
    
    _, err = db.Exec(createTableSQL)
    if err != nil {
        log.Fatal(err)
    }
    
    log.Println("数据库初始化成功")
}

func main() {
    initDB()
    defer db.Close()
    
    // 后续操作...
}

注意defer db.Close() 确保程序退出时正确关闭数据库连接。

4.3 CRUD 操作

定义用户结构体:

type User struct {
    ID        int
    Username  string
    Email     string
    Age       int
    CreatedAt string
}

插入数据

func createUser(username, email string, age int) error {
    query := `INSERT INTO users (username, email, age) VALUES (?, ?, ?)`
    result, err := db.Exec(query, username, email, age)
    if err != nil {
        return err
    }
    
    id, _ := result.LastInsertId()
    log.Printf("用户创建成功,ID: %d", id)
    return nil
}

批量插入(使用预处理语句提升性能):

func batchCreateUsers(users []User) error {
    // 开始事务
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    
    // 准备预处理语句
    stmt, err := tx.Prepare("INSERT INTO users (username, email, age) VALUES (?, ?, ?)")
    if err != nil {
        return err
    }
    defer stmt.Close()
    
    // 批量插入
    for _, u := range users {
        _, err = stmt.Exec(u.Username, u.Email, u.Age)
        if err != nil {
            tx.Rollback()
            return err
        }
    }
    
    // 提交事务
    return tx.Commit()
}

查询单条数据

func getUserByID(id int) (*User, error) {
    query := `SELECT id, username, email, age, created_at FROM users WHERE id = ?`
    row := db.QueryRow(query, id)
    
    var user User
    err := row.Scan(&user.ID, &user.Username, &user.Email, &user.Age, &user.CreatedAt)
    if err != nil {
        if err == sql.ErrNoRows {
            return nil, nil  // 未找到
        }
        return nil, err
    }
    return &user, nil
}

查询多条数据

func getAllUsers() ([]User, error) {
    rows, err := db.Query("SELECT id, username, email, age, created_at FROM users ORDER BY id")
    if err != nil {
        return nil, err
    }
    defer rows.Close()  // 重要:关闭结果集
    
    var users []User
    for rows.Next() {
        var user User
        err = rows.Scan(&user.ID, &user.Username, &user.Email, &user.Age, &user.CreatedAt)
        if err != nil {
            return nil, err
        }
        users = append(users, user)
    }
    
    // 检查遍历过程中的错误
    if err = rows.Err(); err != nil {
        return nil, err
    }
    
    return users, nil
}

更新数据

func updateUserAge(id, age int) error {
    query := `UPDATE users SET age = ? WHERE id = ?`
    result, err := db.Exec(query, age, id)
    if err != nil {
        return err
    }
    
    rowsAffected, _ := result.RowsAffected()
    if rowsAffected == 0 {
        return fmt.Errorf("用户 ID %d 不存在", id)
    }
    return nil
}

删除数据

func deleteUser(id int) error {
    query := `DELETE FROM users WHERE id = ?`
    result, err := db.Exec(query, id)
    if err != nil {
        return err
    }
    
    rowsAffected, _ := result.RowsAffected()
    if rowsAffected == 0 {
        return fmt.Errorf("用户 ID %d 不存在", id)
    }
    return nil
}

4.4 完整示例

package main

import (
    "database/sql"
    "fmt"
    "log"
    
    _ "github.com/mattn/go-sqlite3"
)

type User struct {
    ID    int
    Name  string
    Age   int
    Email string
}

func main() {
    // 1. 打开数据库
    db, err := sql.Open("sqlite3", "./demo.db")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    // 2. 创建表
    createSQL := `CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        age INTEGER,
        email TEXT UNIQUE
    );`
    db.Exec(createSQL)
    
    // 3. 插入数据
    insertSQL := `INSERT INTO users (name, age, email) VALUES (?, ?, ?)`
    result, _ := db.Exec(insertSQL, "张三", 25, "zhangsan@example.com")
    id, _ := result.LastInsertId()
    fmt.Printf("插入成功,ID: %d\n", id)
    
    // 4. 查询数据
    rows, _ := db.Query("SELECT id, name, age, email FROM users")
    defer rows.Close()
    
    for rows.Next() {
        var user User
        rows.Scan(&user.ID, &user.Name, &user.Age, &user.Email)
        fmt.Printf("%d: %s (%d岁) - %s\n", user.ID, user.Name, user.Age, user.Email)
    }
}

五、高级特性

5.1 全文检索(FTS5)

SQLite 内置了全文检索扩展,可以高效地进行文本搜索:

-- 创建全文检索虚拟表
CREATE VIRTUAL TABLE docs USING fts5(title, content);

-- 插入数据
INSERT INTO docs VALUES ('SQLite 教程', 'SQLite 是一个轻量级的嵌入式数据库');
INSERT INTO docs VALUES ('Go 语言入门', 'Go 是 Google 开发的编程语言');

-- 全文搜索
SELECT * FROM docs WHERE docs MATCH '嵌入式';
-- 返回:SQLite 教程

5.2 JSON 支持(SQLite 3.38+)

从 SQLite 3.38 版本开始,原生支持 JSON 操作:

-- 创建带 JSON 字段的表
CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    details JSON
);

-- 插入 JSON 数据
INSERT INTO orders (details) VALUES 
    ('{"items": [{"name": "book", "qty": 2}], "total": 20}');

-- 查询 JSON 字段
SELECT json_extract(details, '$.total') FROM orders;  -- 返回 20
SELECT json_extract(details, '$.items[0].name') FROM orders;  -- 返回 'book'

5.3 内存数据库

在某些场景(如缓存、测试)下,你可能希望数据库完全运行在内存中:

// Go 语言中使用内存数据库
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
    log.Fatal(err)
}
// 所有操作都在内存中进行,程序退出后数据自动销毁

内存数据库的优势是极快的读写速度,适合存储会话级临时数据、测试用例等场景。

5.4 多数据库关联

SQLite 支持在同一个会话中 ATTACH 多个数据库文件:

-- 附加另一个数据库
ATTACH DATABASE 'archive.db' AS archive;

-- 跨数据库查询
SELECT * FROM main.users WHERE id IN (SELECT user_id FROM archive.old_users);

-- 数据迁移
INSERT INTO archive.old_users SELECT * FROM main.users WHERE created_at < '2024-01-01';

六、性能优化与最佳实践

6.1 PRAGMA 配置

PRAGMA 是 SQLite 的特殊命令,用于调整数据库的行为:

-- WAL 模式(Write-Ahead Logging):提升并发读写性能
PRAGMA journal_mode = WAL;

-- 同步模式(性能 vs 安全)
PRAGMA synchronous = NORMAL;   -- OFF: 最快但可能丢数据,NORMAL: 平衡,FULL: 最安全

-- 缓存大小(单位:页,负数表示 KB)
PRAGMA cache_size = -2000;     -- 2MB 缓存

-- 页大小(在新建数据库时设置)
PRAGMA page_size = 4096;

-- 查看当前设置
PRAGMA journal_mode;
PRAGMA synchronous;

WAL 模式说明:传统的回滚日志模式每次写入都要刷盘,WAL 模式将变更先写入单独的 WAL 文件,减少了磁盘 I/O,提升了并发性能。

6.2 事务批量写入

如果需要插入大量数据,使用事务可以大幅提升性能:

func batchInsert(users []User) error {
    tx, _ := db.Begin()
    stmt, _ := tx.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")
    defer stmt.Close()
    
    for _, u := range users {
        stmt.Exec(u.Name, u.Age)
    }
    
    return tx.Commit()  // 一次性提交所有写入
}

原理:没有事务时,每条 INSERT 都会触发一次磁盘同步;使用事务后,所有写入在内存中完成,最后一次性写入磁盘。

6.3 索引优化

索引是提升查询性能的关键,但过多索引会拖慢写入速度:

-- 分析查询计划
EXPLAIN QUERY PLAN SELECT * FROM users WHERE age > 25;
-- 输出说明:SEARCH TABLE users USING INDEX idx_age(使用索引)或 SCAN TABLE users(全表扫描)

-- 创建索引
CREATE INDEX idx_users_age ON users(age);
CREATE INDEX idx_users_name_age ON users(name, age);  -- 复合索引

-- 查看已创建的索引
.indices users

索引设计原则

  • 为 WHERE、ORDER BY、JOIN 中频繁使用的列创建索引
  • 每个表的索引数量控制在 3-5 个
  • 复合索引的顺序很重要:将最常作为等值查询的列放在前面

6.4 数据库维护

-- VACUUM:重建数据库文件,回收空间
VACUUM;

-- ANALYZE:更新统计信息,帮助查询优化器选择更好的执行计划
ANALYZE;

-- 检查完整性
PRAGMA integrity_check;

6.5 常见问题与解决方案

问题 1:数据库锁定(database is locked)

原因:一个连接正在写入时,另一个连接尝试写入(SQLite 在 WAL 模式外一次只允许一个写入者)。

解决方案

  • 启用 WAL 模式:PRAGMA journal_mode = WAL;
  • 缩短事务长度
  • 确保所有连接正确关闭

问题 2:大数据量查询慢

解决方案

  • 使用基于 ID 的分页代替 OFFSET
  • 创建合适的索引
  • 只 SELECT 需要的列,避免 SELECT *

问题 3:数据库文件过大

解决方案

  • 执行 VACUUM 回收空间
  • 考虑使用 AUTO_VACUUM 模式
  • 定期清理历史数据

七、实战项目:笔记管理应用

将以上知识综合起来,我们来构建一个完整的笔记管理 Web 应用,使用 Go + SQLite + HTML 模板。

7.1 项目结构

notes-app/
├── main.go           # 主程序:路由和 HTTP 处理器
├── database.go       # 数据库初始化和连接
├── note.go           # Note 结构体和 CRUD 操作
├── index.html        # 前端页面模板
└── notes.db          # SQLite 数据库文件(运行时生成)

7.2 database.go

package main

import (
    "database/sql"
    "log"
    
    _ "github.com/mattn/go-sqlite3"
)

var db *sql.DB

func initDB() {
    var err error
    db, err = sql.Open("sqlite3", "./notes.db")
    if err != nil {
        log.Fatal(err)
    }
    
    createTableSQL := `
    CREATE TABLE IF NOT EXISTS notes (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );`
    
    _, err = db.Exec(createTableSQL)
    if err != nil {
        log.Fatal(err)
    }
    
    log.Println("数据库初始化完成")
}

7.3 note.go

package main

import "log"

type Note struct {
    ID      int
    Title   string
    Content string
}

func createNote(title, content string) error {
    query := `INSERT INTO notes (title, content) VALUES (?, ?)`
    _, err := db.Exec(query, title, content)
    return err
}

func getAllNotes() ([]Note, error) {
    rows, err := db.Query("SELECT id, title, content FROM notes ORDER BY id DESC")
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    
    var notes []Note
    for rows.Next() {
        var note Note
        err = rows.Scan(&note.ID, &note.Title, &note.Content)
        if err != nil {
            return nil, err
        }
        notes = append(notes, note)
    }
    return notes, nil
}

func deleteNote(id int) error {
    query := `DELETE FROM notes WHERE id = ?`
    result, err := db.Exec(query, id)
    if err != nil {
        return err
    }
    
    rowsAffected, _ := result.RowsAffected()
    if rowsAffected == 0 {
        log.Printf("笔记 ID %d 不存在", id)
    }
    return nil
}

7.4 main.go

package main

import (
    "html/template"
    "log"
    "net/http"
    "strconv"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
    notes, err := getAllNotes()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    tmpl, err := template.ParseFiles("index.html")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    tmpl.Execute(w, notes)
}

func addHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodPost {
        title := r.FormValue("title")
        content := r.FormValue("content")
        if title != "" {
            createNote(title, content)
        }
    }
    http.Redirect(w, r, "/", http.StatusSeeOther)
}

func deleteHandler(w http.ResponseWriter, r *http.Request) {
    idStr := r.FormValue("id")
    if id, err := strconv.Atoi(idStr); err == nil {
        deleteNote(id)
    }
    http.Redirect(w, r, "/", http.StatusSeeOther)
}

func main() {
    initDB()
    defer db.Close()
    
    http.HandleFunc("/", indexHandler)
    http.HandleFunc("/add", addHandler)
    http.HandleFunc("/delete", deleteHandler)
    
    log.Println("服务器启动于 http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

7.5 index.html

<!DOCTYPE html>
<html>
<head>
    <title>我的笔记</title>
    <style>
        body { font-family: Arial; max-width: 800px; margin: 50px auto; padding: 20px; }
        .note { border: 1px solid #ddd; margin: 10px 0; padding: 10px; border-radius: 5px; }
        .note h3 { margin: 0 0 5px 0; }
        .note p { margin: 0; color: #666; }
        .delete-btn { color: red; cursor: pointer; float: right; }
        form { margin: 20px 0; }
        input, textarea { width: 100%; margin: 5px 0; padding: 8px; }
        button { background: #007bff; color: white; border: none; padding: 10px 20px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>笔记应用</h1>
    
    <form method="POST" action="/add">
        <input type="text" name="title" placeholder="标题" required>
        <textarea name="content" rows="3" placeholder="内容"></textarea>
        <button type="submit">添加笔记</button>
    </form>
    
    <h2>我的笔记</h2>
    {{range .}}
    <div class="note">
        <form method="POST" action="/delete" style="display: inline; float: right;">
            <input type="hidden" name="id" value="{{.ID}}">
            <button type="submit" class="delete-btn" style="background: none; color: red; padding: 0;">删除</button>
        </form>
        <h3>{{.Title}}</h3>
        <p>{{.Content}}</p>
    </div>
    {{else}}
    <p>暂无笔记,添加第一条吧!</p>
    {{end}}
</body>
</html>

7.6 运行应用

# 安装依赖
go get github.com/mattn/go-sqlite3

# 运行
go run *.go

# 访问 http://localhost:8080

这个完整的示例涵盖了:

  • SQLite 数据库的初始化和连接
  • CRUD 操作的完整实现
  • 使用 ? 占位符防止 SQL 注入
  • defer rows.Close() 确保资源释放
  • 与 Web 前端的集成

八、总结

SQLite 不是一个“玩具数据库”,而是一个经过二十多年打磨的工业级嵌入式数据库。它的设计哲学是:简单、可靠、快速

通过本文,你应该已经掌握了:

  1. 命令行操作sqlite3 的安装、点命令、SQL 执行
  2. 核心 SQL:建表、增删改查、事务、索引
  3. 编程集成:Go 语言中使用 go-sqlite3 驱动进行 CRUD
  4. 高级特性:全文检索、JSON 支持、内存数据库
  5. 性能优化:PRAGMA 配置、事务批量写入、索引设计
  6. 实战应用:完整的笔记管理 Web 应用

选型建议:如果你是以下场景,SQLite 是绝佳选择:

  • 移动应用、桌面软件、物联网设备
  • 中小型网站(日活 < 10 万)
  • 数据分析和原型验证
  • 任何需要嵌入式数据库的场景

进一步学习资源

希望这篇指南能帮助你快速上手 SQLite,并在实际项目中灵活运用!