💻 第八章 一用就会的数据库
📄 一句话概括

数据对象是应用与 DBMS 之间的一道门——SQL 关进一间屋子,改表结构只改一处。

📝 本节和前面几节的关系

会写 SQL 了,本节的规矩是:别让它散落各处——用数据对象把 SQL 收拢起来。

一、散落 SQL 的痛

如果应用里到处直写 SQL:界面一处、统计一处、导入一处——同一张表被改了结构,就要满世界找 SQL 改; 更要命的是漏改:一处忘了改,就在某个角落静悄悄地坏掉,很久才被发现; SQL 和数据表的【知识】被撕成了许多小片散落各处——这正是 7.4 讲的【改动牵连】。

二、数据对象:一扇门

数据对象(常叫 DAO,Data Access Object)是专门负责和 DBMS 打交道的类:所有 SQL 都写在它里面; 应用侧只调用它的方法:add()、find()、change_stock()——看不见一句 SQL; 表结构一变,只改数据对象这一处,应用代码一行不动。

三、又见封装

这就是 7.4 的封装在数据库侧的重演:数据对象是围墙,SQL 是围墙里的细节; 好处也一样:围墙内随便改(换表名、加索引、换 SQL 写法),围墙外的应用岁月静好; 【⚠️ 2026 现状】今天很多项目进一步用 ORM(对象关系映射),让数据对象自动生成——但【把数据访问收在一处】的原则没变。

四、动手 Demo:用数据对象封装 SQL

写一个 BookDAO 数据对象,应用只调方法,不写一句 SQL。

import sqlite3
class BookDAO:
    def __init__(self, con): self.con = con
    def add(self, bid, title, stock):
        self.con.execute("INSERT INTO book VALUES (?, ?, ?)", (bid, title, stock))
    def change_stock(self, bid, delta):
        self.con.execute("UPDATE book SET stock = stock + ? WHERE id = ?", (delta, bid))
    def all(self):
        return list(self.con.execute("SELECT id, title, stock FROM book"))
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE book (id INTEGER PRIMARY KEY, title TEXT, stock INTEGER)")
dao = BookDAO(con)
dao.add(1, "三国演义", 5)
dao.change_stock(1, -1)
print(dao.all())

实跑输出:

--------------------------------------------------------------------
使用数据对象向 DBMS 发送 SQL 语句
--------------------------------------------------------------------

应用程序若到处直接写 SQL, 改一次表结构就要满世界改。
更规矩的做法: 让一个【数据对象】专门管数据库, 应用只跟它说话:

    应用侧代码只跟数据对象打交道:
        dao.add(1, '三国演义', 5)
        dao.change_stock(1, -1)
        for row in dao.all(): print(row)
        (1, '三国演义', 4)

  做法           应用里写什么              改表结构时要改几处
  ------------------------------------------------------------
  直接写 SQL     散落各处的 SQL 语句       很多处
  经数据对象     只调用 add/all 等方法     1 处(数据对象里)

    数据对象把 SQL 关进一间屋子——又是 7.4 封装思想在数据库侧的重演。

换掉表名、加一列,只需改 BookDAO 内部——应用侧三行调用一动不动。 数据对象还把 SQL 参数化(用 ? 占位),顺手挡掉了注入攻击——19 课安全课的老朋友。

30 秒实验

  1. 说出数据对象带来的两个好处:改结构省事、SQL 收拢一处。
  2. 把你写过的一处直写 SQL 的代码,改造成一个最小数据对象。

常见误区

  1. 以为数据对象是多余的中间层——它是把改动关进围墙的设施,省的是以后每次改的时间。
  2. 以为有了数据对象就万事大吉——SQL 写得不带 WHERE,照样出事故。
自测三问(点开对答案) 1. 散落 SQL 的核心痛点是什么? —— 改表结构要满世界改,漏改一处就在角落坏掉。 2. 数据对象的作用? —— 把 SQL 收拢到一个类里,应用只调方法、不碰 SQL。 3. 数据对象与 7.4 的哪个思想同源? —— 封装——内部细节对外隐藏,只留公开方法。

相关笔记