Python + sqlite3 本地 SQLite 数据库操作实战:完整 CRUD 入门教程

Python + sqlite3 本地 SQLite 数据库操作实战:从建库建表到完整 CRUD

对于 Python 后端初学者来说,数据库操作是必须掌握的基础能力。很多 Web 项目、接口服务、爬虫程序、桌面工具都会涉及数据的保存、查询和更新。

如果你刚开始学习数据库,不一定要马上安装 MySQL、PostgreSQL 这类独立数据库服务。Python 标准库自带的 sqlite3 就可以直接操作 SQLite 本地数据库,非常适合学习 SQL、练习 CRUD、开发小型本地项目。

本文将通过一个"用户信息管理"的例子,带你完成:

  • sqlite3 库介绍
  • 创建 SQLite 数据库
  • 创建数据表
  • 插入数据
  • 查询数据
  • 修改数据
  • 删除数据
  • Python ORM 思想简单介绍
  • 完整 CRUD 演示代码

一、sqlite3 库介绍

sqlite3 是 Python 标准库自带的 SQLite 数据库操作模块,不需要额外安装。

SQLite 是一种轻量级嵌入式数据库,它的特点是:

  • 不需要单独启动数据库服务
  • 数据保存在本地 .db 文件中
  • 适合学习、测试、小型工具、桌面程序和轻量级后端项目
  • 支持常见 SQL 语句,例如 CREATE TABLEINSERTSELECTUPDATEDELETE

在 Python 中使用 SQLite,只需要导入:

python 复制代码
import sqlite3

一个典型的数据库操作流程如下:

python 复制代码
import sqlite3

conn = sqlite3.connect("demo.db")
cursor = conn.cursor()

cursor.execute("SELECT sqlite_version()")
print(cursor.fetchone())

conn.close()

这里有几个重要概念:

  • connect():连接数据库,如果数据库文件不存在,会自动创建
  • connection:数据库连接对象,通常命名为 conn
  • cursor:游标对象,用来执行 SQL 语句
  • execute():执行 SQL
  • commit():提交事务,让新增、修改、删除真正生效
  • close():关闭数据库连接

二、创建数据库

使用 SQLite 创建数据库非常简单,只需要连接一个 .db 文件即可。

python 复制代码
import sqlite3

conn = sqlite3.connect("student.db")
conn.close()

运行后,当前目录下会生成一个 student.db 文件。

如果文件已经存在,sqlite3.connect() 会直接连接这个数据库;如果文件不存在,就会自动创建。

在实际项目中,也可以把数据库文件放到指定目录:

python 复制代码
conn = sqlite3.connect(r"D:\data\student.db")

Windows 路径前面加 r,可以避免反斜杠被当作转义字符。

三、创建数据表

数据库文件创建好以后,还需要创建数据表。数据表类似 Excel 中的一张工作表,用来存储某一类数据。

下面创建一张 users 表,用来保存用户信息:

python 复制代码
import sqlite3

conn = sqlite3.connect("app.db")
cursor = conn.cursor()

sql = """
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER,
    email TEXT UNIQUE,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
"""

cursor.execute(sql)
conn.commit()
conn.close()

字段说明:

  • id:用户编号,主键,自增
  • name:用户名,不能为空
  • age:年龄,整数类型
  • email:邮箱,唯一
  • created_at:创建时间,默认使用当前时间

CREATE TABLE IF NOT EXISTS 的意思是:如果表不存在就创建,如果已经存在就不重复创建,避免程序重复运行时报错。

四、插入数据

插入数据使用 INSERT INTO 语句。

python 复制代码
import sqlite3

conn = sqlite3.connect("app.db")
cursor = conn.cursor()

sql = "INSERT INTO users (name, age, email) VALUES (?, ?, ?)"
cursor.execute(sql, ("张三", 22, "zhangsan@example.com"))

conn.commit()
conn.close()

这里需要重点注意:推荐使用 ? 占位符传参,而不是直接拼接字符串。

推荐写法:

python 复制代码
cursor.execute(
    "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
    ("李四", 25, "lisi@example.com")
)

不推荐写法:

python 复制代码
name = "李四"
sql = "INSERT INTO users (name) VALUES ('" + name + "')"

字符串拼接 SQL 容易出现 SQL 注入风险,也容易因为引号、特殊字符导致 SQL 报错。

如果要一次插入多条数据,可以使用 executemany()

python 复制代码
users = [
    ("王五", 28, "wangwu@example.com"),
    ("赵六", 30, "zhaoliu@example.com"),
    ("钱七", 24, "qianqi@example.com")
]

cursor.executemany(
    "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
    users
)
conn.commit()

五、查询数据

查询数据使用 SELECT 语句。

查询所有用户:

python 复制代码
cursor.execute("SELECT id, name, age, email, created_at FROM users")
rows = cursor.fetchall()

for row in rows:
    print(row)

fetchall() 会获取所有查询结果,返回一个列表,每一行是一个元组。

如果只想查询一条数据,可以使用 fetchone()

python 复制代码
cursor.execute("SELECT id, name, age, email FROM users WHERE id = ?", (1,))
user = cursor.fetchone()
print(user)

注意 (1,) 不是写错了。Python 中只有一个元素的元组,必须加逗号。

也可以按条件查询:

python 复制代码
cursor.execute(
    "SELECT id, name, age, email FROM users WHERE age >= ?",
    (25,)
)
rows = cursor.fetchall()

六、修改数据

修改数据使用 UPDATE 语句。

下面把 id=1 的用户年龄改为 23

python 复制代码
cursor.execute(
    "UPDATE users SET age = ? WHERE id = ?",
    (23, 1)
)
conn.commit()

如果想同时修改多个字段,可以这样写:

python 复制代码
cursor.execute(
    "UPDATE users SET name = ?, email = ? WHERE id = ?",
    ("张三丰", "zhangsanfeng@example.com", 1)
)
conn.commit()

执行 UPDATE 时一定要小心 WHERE 条件。如果没有 WHERE,可能会把整张表的数据都修改掉。

七、删除数据

删除数据使用 DELETE 语句。

删除 id=1 的用户:

python 复制代码
cursor.execute("DELETE FROM users WHERE id = ?", (1,))
conn.commit()

同样要注意:DELETE 语句必须谨慎使用 WHERE 条件。

危险写法:

python 复制代码
cursor.execute("DELETE FROM users")

这会删除 users 表中的所有数据。

如果只是想清空测试数据,可以明确知道后果后再执行。

八、事务和异常处理

在数据库操作中,新增、修改、删除都需要提交事务。

如果执行成功,就调用:

python 复制代码
conn.commit()

如果执行失败,可以回滚:

python 复制代码
conn.rollback()

更推荐使用 try...except...finally 管理数据库连接:

python 复制代码
import sqlite3

conn = None

try:
    conn = sqlite3.connect("app.db")
    cursor = conn.cursor()
    cursor.execute(
        "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
        ("测试用户", 20, "test@example.com")
    )
    conn.commit()
except sqlite3.Error as e:
    if conn:
        conn.rollback()
    print("数据库操作失败:", e)
finally:
    if conn:
        conn.close()

这样可以避免程序异常时数据库连接没有关闭。

九、Python ORM 思想简单介绍

前面我们直接写 SQL 操作数据库,这种方式直观、灵活,也适合初学者理解数据库底层逻辑。

在真实后端项目中,还经常会使用 ORM。

ORM 的全称是 Object Relational Mapping,中文通常叫"对象关系映射"。它的核心思想是:

把数据库中的表映射成 Python 类,把表中的一行数据映射成 Python 对象,把字段映射成对象属性。

例如数据库中有一张 users 表:

text 复制代码
users 表
id | name | age | email

在 ORM 中,可能会定义一个 User 类:

python 复制代码
class User:
    def __init__(self, id, name, age, email):
        self.id = id
        self.name = name
        self.age = age
        self.email = email

查询数据库后,可以把一行数据转换成对象:

python 复制代码
row = (1, "张三", 22, "zhangsan@example.com")
user = User(row[0], row[1], row[2], row[3])

print(user.name)

这样做的好处是:

  • 代码更接近面向对象写法
  • 业务层可以少写 SQL
  • 数据结构更清晰
  • 大项目中更容易维护

Python 中常见 ORM 框架包括:

  • SQLAlchemy
  • Django ORM
  • Peewee

不过,建议初学者先掌握基础 SQL 和 sqlite3,再学习 ORM。因为 ORM 本质上也是帮你生成和执行 SQL,如果完全不了解 SQL,后面排查问题会比较困难。

十、完整 CRUD 演示代码

下面是一份完整示例代码,包含创建数据库、创建数据表、插入数据、查询数据、修改数据、删除数据,以及一个简单的对象转换示例。

你可以保存为 sqlite_crud_demo.py 后直接运行。

python 复制代码
import sqlite3
from dataclasses import dataclass


DB_NAME = "app.db"


@dataclass
class User:
    id: int
    name: str
    age: int
    email: str
    created_at: str


def get_connection():
    return sqlite3.connect(DB_NAME)


def create_table():
    conn = get_connection()
    cursor = conn.cursor()

    sql = """
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        age INTEGER,
        email TEXT UNIQUE,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    )
    """

    cursor.execute(sql)
    conn.commit()
    conn.close()


def insert_user(name, age, email):
    conn = get_connection()
    cursor = conn.cursor()

    try:
        cursor.execute(
            "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
            (name, age, email)
        )
        conn.commit()
        print("插入成功,用户 ID:", cursor.lastrowid)
    except sqlite3.Error as e:
        conn.rollback()
        print("插入失败:", e)
    finally:
        conn.close()


def insert_many_users(users):
    conn = get_connection()
    cursor = conn.cursor()

    try:
        cursor.executemany(
            "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
            users
        )
        conn.commit()
        print("批量插入成功")
    except sqlite3.Error as e:
        conn.rollback()
        print("批量插入失败:", e)
    finally:
        conn.close()


def query_all_users():
    conn = get_connection()
    cursor = conn.cursor()

    cursor.execute("SELECT id, name, age, email, created_at FROM users")
    rows = cursor.fetchall()
    conn.close()

    return [User(*row) for row in rows]


def query_user_by_id(user_id):
    conn = get_connection()
    cursor = conn.cursor()

    cursor.execute(
        "SELECT id, name, age, email, created_at FROM users WHERE id = ?",
        (user_id,)
    )
    row = cursor.fetchone()
    conn.close()

    if row is None:
        return None

    return User(*row)


def update_user_age(user_id, new_age):
    conn = get_connection()
    cursor = conn.cursor()

    cursor.execute(
        "UPDATE users SET age = ? WHERE id = ?",
        (new_age, user_id)
    )
    conn.commit()

    if cursor.rowcount == 0:
        print("没有找到要修改的用户")
    else:
        print("修改成功")

    conn.close()


def delete_user(user_id):
    conn = get_connection()
    cursor = conn.cursor()

    cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
    conn.commit()

    if cursor.rowcount == 0:
        print("没有找到要删除的用户")
    else:
        print("删除成功")

    conn.close()


def print_users(users):
    for user in users:
        print(
            f"ID: {user.id}, 姓名: {user.name}, 年龄: {user.age}, "
            f"邮箱: {user.email}, 创建时间: {user.created_at}"
        )


if __name__ == "__main__":
    create_table()

    insert_user("张三", 22, "zhangsan@example.com")

    insert_many_users([
        ("李四", 25, "lisi@example.com"),
        ("王五", 28, "wangwu@example.com"),
        ("赵六", 30, "zhaoliu@example.com")
    ])

    print("\n查询所有用户:")
    users = query_all_users()
    print_users(users)

    print("\n查询 ID 为 1 的用户:")
    user = query_user_by_id(1)
    print(user)

    print("\n修改 ID 为 1 的用户年龄:")
    update_user_age(1, 23)

    print("\n修改后的用户列表:")
    users = query_all_users()
    print_users(users)

    print("\n删除 ID 为 2 的用户:")
    delete_user(2)

    print("\n删除后的用户列表:")
    users = query_all_users()
    print_users(users)

十一、代码运行说明

运行代码:

bash 复制代码
python sqlite_crud_demo.py

第一次运行后,当前目录下会生成:

text 复制代码
app.db

这个文件就是 SQLite 数据库文件。

如果重复运行示例代码,可能会因为 email 字段设置了唯一约束而出现类似错误:

text 复制代码
UNIQUE constraint failed: users.email

这是正常现象,说明同一个邮箱不能重复插入。测试时可以删除 app.db 后重新运行,或者修改示例中的邮箱地址。

十二、后端初学者需要掌握的重点

学习 sqlite3 时,建议重点掌握下面几个点:

  • 数据库连接:sqlite3.connect()
  • 创建游标:conn.cursor()
  • 执行 SQL:cursor.execute()
  • 参数化 SQL:使用 ? 占位符
  • 提交事务:conn.commit()
  • 回滚事务:conn.rollback()
  • 关闭连接:conn.close()
  • 查询一条数据:fetchone()
  • 查询多条数据:fetchall()
  • 判断影响行数:cursor.rowcount

对于后端开发来说,数据库操作不仅仅是会写 SQL,还要注意安全性和稳定性。例如参数化 SQL 可以降低 SQL 注入风险,事务处理可以避免数据写入一半就失败的问题。

十三、总结

本文通过 Python 标准库 sqlite3 演示了本地 SQLite 数据库的基本操作,包括:

  • 创建数据库
  • 创建数据表
  • 插入数据
  • 查询数据
  • 修改数据
  • 删除数据
  • 简单理解 ORM 思想
  • 使用 dataclass 把查询结果转换成 Python 对象
  • 完整 CRUD 示例代码

对于 Python 后端初学者来说,SQLite 是非常适合作为第一门数据库实践工具的。它不需要安装数据库服务,只需要一个 .db 文件就能完成完整的数据增删改查。掌握这些基础之后,再学习 MySQL、PostgreSQL、SQLAlchemy 或 Django ORM,会更加顺畅。

相关推荐
rit84324991 小时前
水声通信Rake接收机-MATLAB
开发语言·matlab
sindyra1 小时前
享元模式(Flyweight Pattern)
java·开发语言·设计模式·享元模式·优缺点
NG WING YIN1 小时前
一鍵計算稅項支出
python
m0_736439301 小时前
如何处理无法修改主键列的问题_先删除AUTO_INCREMENT再移除主键的顺序
jvm·数据库·python
codingPower1 小时前
ApplicationListener 和 SpringApplicationRunListener 深度解析对比
java·开发语言·spring boot
2401_898717661 小时前
如何在 SvelteKit 中为动态加载的图片正确实现悬停显示覆盖层
jvm·数据库·python
m0_702036531 小时前
如何在MongoDB中实现按时间跨度的分片路由_时间序列范围分片与冷热节点架构.txt
jvm·数据库·python
2401_884454151 小时前
golang如何使用Fiber高性能框架_golang Fiber框架入门教程
jvm·数据库·python
ㄟ留恋さ寂寞1 小时前
Golang怎么读取和修改图片EXIF信息_Golang如何用goexif提取照片的拍摄时间和GPS位置【方法】
jvm·数据库·python