PostgreSQL安装与ACID介绍

0 阅读13分钟

 第一阶段:安装与环境配置

这一阶段的核心目标是用最短时间、最顺畅的方式让你拥有一个可以动手实践的 PostgreSQL 环境。我们将分平台介绍,请按你的操作系统选择。


1. PostgreSQL 安装(各平台)

A. Windows 平台安装(推荐最简单的安装器)

步骤 1:下载安装器

  • 前往 PostgreSQL 官方下载页面
  • 点击 Download the installer
  • 选择适合自己系统(64位或32位)的版本下载。例如:PostgreSQL 15.x for Windows x86-64。

步骤 2:运行安装

  1. 双击下载好的 .exe 文件(如 postgresql-15.x-windows-x64.exe)。

  2. 重要设置点

    • 安装路径:默认即可(C:\Program Files\PostgreSQL\15)。

    • 选择组件:务必勾选:

      • PostgreSQL Server
      • pgAdmin 4 (这是GUI图形化管理工具)
      • Command Line Tools (包含 psql 命令行工具)
      • Stack Builder (可选,用于安装附加驱动)
    • 数据目录:默认(C:\Program Files\PostgreSQL\15\data)。

    • 设置密码:这是你的 超级用户 (postgres) 密码!一定记住!例如:mysecretpassword

    • 端口:默认 5432(除非该端口已被占用)。

    • 语言环境:保持默认或选择 Chinese (Simplified), China

步骤 3:完成安装

  • 一路点击 “Next” 直到完成。在最后一步,不要取消勾选 “Launch Stack Builder? ”,直接点 “Finish”。
  • 安装完成!Windows 的服务列表中会增加一个 postgresql-x64-15 的服务,并自动启动。

B. macOS 平台安装(推荐两种方法)

方法 1:使用 Homebrew(最简单快捷,推荐开发者)

  1. 打开 终端

  2. 如果你没有 Homebrew,先安装它:

    <BASH>
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
  3. 使用 Homebrew 安装 PostgreSQL:

    <BASH>
    brew install postgresql@15
    
  4. 启动 PostgreSQL 服务(每次开机后可能需要运行一次):

    <BASH>
    brew services start postgresql@15
    
  5. 注意:Homebrew 安装的 PostgreSQL,默认超级用户是你的系统用户名,且没有密码。数据目录通常在 /opt/homebrew/var/postgresql@15

方法 2:官方图形化安装器

  • 下载 EnterpriseDB 提供的 macOS 安装包
  • 运行 .dmg 文件,像安装普通 App 一样拖拽即可。
  • 安装过程与 Windows 版类似,会提示设置 postgres 用户的密码,并安装 pgAdmin。

C. Linux 平台(以 Ubuntu/Debian 为例)

使用 apt 包管理器安装:

<BASH>
# 1. 更新包列表
sudo apt update
# 2. 安装 PostgreSQL 和常用工具包
sudo apt install postgresql postgresql-contrib
# 3. 查看服务状态
sudo systemctl status postgresql
# 4. PostgreSQL 会自动启动。默认超级用户也叫 `postgres`。

重要:Linux 安装后,需要切换到 postgres 系统用户来操作数据库。


2. pgAdmin 工具的安装使用

A. pgAdmin 4 - PostgreSQL 官方 GUI 工具
  • 如果你在 Windows/macOS 使用官方安装器,它已经一并安装了!

  • 找到并启动它:在开始菜单(Windows)或启动台(macOS)搜索 “pgAdmin 4”。

  • 首次连接配置

    1. 启动后,它会要求你设置一个 主密码(Master Password) ,用于保护你的数据库连接信息。请牢记。

    2. 在左侧 “Browser” 窗口,右键点击 Servers -> Register -> Server...

    3. 在 “General” 选项卡的 “Name” 里,随意起个名字,如 MyLocalPG

    4. 在 “Connection” 选项卡:

      • Host name/addresslocalhost
      • Port5432
      • Maintenance databasepostgres (默认数据库)
      • Usernamepostgres (Windows/图形化安装器) 或你的系统用户名(macOS Homebrew安装)
      • Password: 你安装时设置的密码(如果是Homebrew无密码,则留空)
    5. 点击 “Save”。如果一切顺利,左侧就能展开看到你的数据库服务器和其中的数据库了。

pgAdmin 界面概览

  • 左侧浏览器:管理服务器、数据库、表等对象。
  • 顶部工具栏:执行查询、导入导出等。
  • 中部主窗口:查询工具、仪表板等。

3. 命令行工具 psql 的基本操作

这是最重要的一步,无论 GUI 多方便,psql 命令行依然是管理和调试数据库最可靠、最高效的方式。

如何启动 psql
  • Windows

    • 方法 1:在开始菜单找到 “SQL Shell (psql)” 并打开。
    • 方法 2:在 cmd 或 PowerShell 中直接输入 psql -U postgres
  • macOS / Linux

    • 打开终端。

    • 关键步骤:需要以正确的用户身份登录。

      • 如果你是 官方安装器/apt安装sudo -u postgres psql
      • 如果你是 macOS Homebrew 安装psql postgres (直接用你的用户名)
psql 基础命令(交互式命令,以 `` 开头)

当你看到 postgres=# 这样的提示符时,说明你已经成功连接!

# 1. 列出所有数据库
\l
或
\l+
# 2. 连接到另一个数据库 (假设有一个叫 mydb 的数据库)
\c mydb
# 3. 列出当前数据库的所有表
\dt
# 4. 查看表结构 (例如查看 users 表)
\d users
\d+ users # 更详细
# 5. 列出所有角色(用户)
\du
# 6. 执行外部 SQL 文件
\i /path/to/your/file.sql
# 7. 开启执行时间计时
\timing
# 8. 设置输出格式 (更易读)
\x auto
# 9. 退出 psql
\q
在 psql 中执行 SQL 语句

直接输入 SQL 语句,以分号 (;) 结尾,然后按回车执行。

-- 示例:创建一个测试数据库
CREATE DATABASE testdb;
-- 连接到新数据库
\c testdb
-- 创建一张表
CREATE TABLE person (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT
);
-- 插入一些数据
INSERT INTO person (name, age) VALUES ('张三', 25), ('李四', 30);
-- 查询数据
SELECT * FROM person;
-- 更新数据
UPDATE person SET age = 26 WHERE name = '张三';
-- 删除数据
DELETE FROM person WHERE name = '李四';

本阶段实战任务(必须完成)

  1. 成功安装 PostgreSQL 在你的操作系统上。

  2. 成功连接

    • 使用 psql 命令行连接到 postgres 数据库。
    • (可选但推荐)使用 pgAdmin 或 DBeaver 图形化连接。
  3. 执行你的第一个 SQL

    • 通过 psql,完成以下操作:

      • 创建一个名为 myfirstdb 的数据库。
      • 连接到这个数据库。
      • 创建一个 books 表,包含 idtitleauthorprice 字段。
      • 插入 2-3 条图书数据。
      • 执行一次查询,显示所有图书。
  4. 理解概念

    • postgres 既是默认数据库名,也是一个默认的超级用户名。
    • localhost:5432 是 PostgreSQL 默认的监听地址和端口。

ACID:数据库事务的四大保证

ACID 是数据库事务必须满足的四个关键特性,确保数据的可靠性和一致性。

ACID 定义

A - Atomicity     原子性
C - Consistency    一致性
I - Isolation      隔离性
D - Durability     持久性

1. 原子性 (Atomicity)

"要么全部完成,要么全部不完成"

通俗解释: 事务就像原子一样不可分割。要么所有操作都成功,要么全部回滚到事务开始前的状态。

例子: 银行转账

BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user = 'A';  -- A扣款
UPDATE accounts SET balance = balance + 100 WHERE user = 'B';  -- B收款
COMMIT;

如果第二步失败(B账户不存在),第一步的扣款操作会自动撤销。


2. 一致性 (Consistency)

"事务必须始终保持数据的完整性约束"

通俗解释: 事务前后,数据库都必须处于合法的状态,遵守所有的规则和约束。

约束类型:

  • 主键约束:主键必须唯一
  • 外键约束:外键必须引用有效记录
  • 唯一约束:某些列值不能重复
  • 数据范围:如余额不能为负数

例子:

-- 错误:转账金额大于余额
UPDATE accounts SET balance = balance - 1000 WHERE balance = 500;
-- 事务会失败,因为余额不能为负数

3. 隔离性 (Isolation)

"并发事务互不干扰"

通俗解释: 多个事务同时执行时,它们各自的操作应该像顺序执行一样,互不影响。

隔离级别:

-- PostgreSQL 隔离级别
SET TRANSACTION ISOLATION LEVEL 
  READ UNCOMMITTED   -- 可能读到脏数据(最低)
  | READ COMMITTED   -- 只能读已提交的数据(默认)
  | REPEATABLE READ  -- 可重复读
  | SERIALIZABLE;    -- 完全隔离(最高)

1. 读未提交 (READ UNCOMMITTED)

最低隔离级别:可能读取到其他事务未提交的数据

PostgreSQL 实际不支持这个级别(它直接升级为 READ COMMITTED) 但概念很重要:

-- 会话A
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;  
-- 还没提交!
-- 会话B (READ UNCOMMITTED 下)
BEGIN TRANSACTION ISOLATION LEVEL ...;
SELECT balance FROM accounts WHERE id = 1;  
-- ❌ 可能看到 500(脏读)
-- 如果A回滚,B看到的数据就是错的!

现实比喻:看到同事写了半截的邮件,结果他删掉不发了

2. 读已提交 (READ COMMITTED)

PostgreSQL 默认级别:只能读取已提交的数据

-- 演示:两个转账同时进行
CREATE TABLE accounts (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    balance DECIMAL(10,2)
);
INSERT INTO accounts VALUES 
(1, '小明', 1000),
(2, '小红', 1000);
-- 会话A:小明转200给小红
BEGIN;  -- PostgreSQL默认READ COMMITTED
UPDATE accounts SET balance = balance - 200 WHERE id = 1;  -- 小明变800
-- 还没提交...
-- 会话B:查看余额
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  
-- ✅ 结果:1000(看到的是事务开始前的快照)
-- 会话A提交
COMMIT;
-- 会话B再次查询
SELECT balance FROM accounts WHERE id = 1;  
-- ✅ 结果:800(看到新提交的数据)
COMMIT;

但有问题:不可重复读

-- 会话A
BEGIN;
-- 第一次查询
SELECT SUM(balance) FROM accounts;
-- 结果:2000
-- 会话B(同时)
BEGIN;
UPDATE accounts SET balance = balance + 500 WHERE id = 1;
COMMIT;  -- 提交了!
-- 会话A 再次查询
SELECT SUM(balance) FROM accounts;
-- ❌ 结果:2500(和第一次不一样!)
COMMIT;

3. 可重复读 (REPEATABLE READ)

同一事务内,多次读取同一数据结果一致

-- 会话A
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 第一次查询
SELECT balance FROM accounts WHERE id = 1;
-- 结果:800
-- 会话B(更新并提交)
BEGIN;
UPDATE accounts SET balance = 1000 WHERE id = 1;
COMMIT;
-- 会话A 第二次查询(在同一事务内)
SELECT balance FROM accounts WHERE id = 1;
-- ✅ 结果:800(和第一次一样,不受B影响)
COMMIT;  -- 提交后才看到1000

现实比喻

  • 你早上8点打开报表,一直看到10点
  • 别人9点更新了数据
  • 但你看到的还是8点时的数据快照

🔴 但还有问题:幻读 (Phantom Read)

-- 会话A(统计用户)
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT COUNT(*) FROM accounts WHERE balance > 500;
-- 结果:2
-- 会话B(插入新用户)
BEGIN;
INSERT INTO accounts VALUES (3, '小刚', 600);
COMMIT;
-- 会话A 再次统计
SELECT COUNT(*) FROM accounts WHERE balance > 500;
-- ✅ 结果:2(不会看到新用户)
COMMIT;

等等,这不是没问题吗? 看这个:

-- 会话A(想找出所有余额>500的用户)
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT id FROM accounts WHERE balance > 500;
-- 返回:1, 2
-- 会话B(插入新用户)
BEGIN;
INSERT INTO accounts VALUES (3, '小刚', 600);
COMMIT;
-- 会话A 尝试更新这些用户
UPDATE accounts SET balance = balance * 1.1 
WHERE balance > 500;
-- ❌ PostgreSQL会报错:ERROR: could not serialize access
-- 因为发现条件范围被修改了

4. 序列化 (SERIALIZABLE)

最高隔离级别:完全串行执行的效果

-- 经典的"丢失更新"问题演示
-- 会话A
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT balance FROM accounts WHERE id = 1;
-- 看到:800(想加400奖金)
-- 会话B(同时)
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT balance FROM accounts WHERE id = 1;
-- 同样看到:800(想扣300罚款)
-- 会话A
UPDATE accounts SET balance = 800 + 400 WHERE id = 1;
COMMIT;  -- 成功,余额变1200
-- 会话B
UPDATE accounts SET balance = 800 - 300 WHERE id = 1;
-- ❌ ERROR: could not serialize access due to concurrent update
ROLLBACK;  -- 必须重试

现实比喻

  • 两个售票员同时卖最后一张票
  • 系统只让一个人成功,另一个失败重试
  • 避免"一票两卖"

4. 持久性 (Durability)

"一旦提交,永不丢失"

通俗解释: 事务提交后,即使系统崩溃、断电,数据也不会丢失。

实现机制:

┌─────────────────────────────────────┐
│      PostgreSQL 持久化保证          │
├─────────────────────────────────────┤
│ 1. WAL(Write-Ahead Logging)       │
│    先写日志,再写数据               │
│                                        │
│ 2. Checkpoint                      │
│    定期将内存数据刷到磁盘           │
│                                        │
│ 3. 同步提交                        │
│    确保日志写入磁盘后才返回成功     │
└─────────────────────────────────────┘

关系型数据库 vs 非关系型数据库

关系型数据库 (RDBMS)

特点:

  • 使用表格(Table)存储数据,行=记录,列=字段
  • 遵循ACID原则(原子性、一致性、隔离性、持久性)
  • 使用SQL语言操作
  • 数据间有关联(外键)

代表产品:

  • MySQL
  • PostgreSQL
  • Oracle
  • SQL Server

适用场景:

  • 需要复杂查询和事务处理的场景
  • 数据结构固定、关系明确的应用
  • 银行系统、ERP系统等

非关系型数据库 (NoSQL)

特点:

  • 不使用固定表格结构
  • 灵活的数据模型
  • 高可扩展性和高性能
  • 不强制要求ACID特性

四种主要类型:

类型特点代表产品适用场景
文档型类似JSON格式存储MongoDB内容管理系统
键值型简单的键值对Redis缓存、会话存储
列存储按列组织数据Cassandra大数据分析
图数据库存储节点和关系Neo4j社交网络、推荐系统

二、数据库关系类型

1. 一对一关系

概念: 一个表的每条记录对应另一个表的仅一条记录。

现实举例:

  • 用户 ↔ 用户身份证信息
  • 学生 ↔ 学籍档案(一对一)

SQL实现:

-- 用户表
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);
-- 身份证表(外键引用用户id)
CREATE TABLE id_cards (
    user_id INT PRIMARY KEY,
    id_number VARCHAR(20),
    FOREIGN KEY (user_id) REFERENCES users(id)
    -- 也可以添加 UNIQUE 约束确保一对一
);

2. 一对多关系

概念: 一个表的记录对应另一个表的多条记录。

现实举例:

  • 部门 → 员工(一个部门有多个员工)
  • 班级 → 学生(一个班级多个学生)
  • 用户 → 订单(一个用户多个订单)

SQL实现:

-- "一"方:部门表
CREATE TABLE departments (
    dept_id INT PRIMARY KEY,
    dept_name VARCHAR(50)
);
-- "多"方:员工表(包含外键)
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(50),
    dept_id INT,  -- 外键字段
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);

3. 多对多关系

概念: 两个表的记录可以相互对应多条记录。

现实举例:

  • 学生 ↔ 课程(一个学生选多门课,一门课多个学生选)
  • 产品 ↔ 订单(一个订单多种产品,一个产品在多个订单中)
  • 作者 ↔ 书籍(一个作者多本书,一本书多个作者)

SQL实现: 需要中间表(连接表)

<SQL>
-- 学生表
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    name VARCHAR(50)
);
-- 课程表
CREATE TABLE courses (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(50)
);
-- 中间表(连接表)
CREATE TABLE student_courses (
    student_id INT,
    course_id INT,
    enrollment_date DATE,
    PRIMARY KEY (student_id, course_id),  -- 复合主键
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);

三、视觉化对比

一对一关系:

<TEXT>
用户表        身份证表
┌─────┐      ┌───────────┐
│用户A│─────→│身份证A    │
├─────┤      ├───────────┤
│用户B│─────→│身份证B    │
└─────┘      └───────────┘

一对多关系:

<TEXT>
部门表        员工表
┌─────┐      ┌──────┐
│IT部 │──┐   │小王  │ ←─┐
├─────┤  ├─→ │小李  │   │
│HR部 │──┤   ├──────┤   │
└─────┘  └─→ │小张  │   │
            └──────┘   │
             部门ID指向IT部

多对多关系:

<TEXT>
学生表        中间表        课程表
┌─────┐      ┌───────┐   ┌──────┐
│张三 │─────→│张 数学│←──│数学  │
├─────┤      ├───────┤   ├──────┤
│李四 │─────→│张 英语│   │英语  │
│     │      ├───────┤   ├──────┤
│     │      │李 数学│   │物理  │
└─────┘      │李 物理│   └──────┘
              └───────┘

四、实际应用建议

选择建议:

  1. 需要事务和复杂查询 → 关系型数据库
  2. 快速扩展、灵活结构 → 非关系型数据库
  3. 混合架构:主流应用使用RDBMS + 特定功能使用NoSQL(如Redis缓存)

关系设计技巧:

  1. 分析业务需求时,先确定实体间的真实关系
  2. 多对多关系一定需要中间表
  3. 外键约束保证数据完整性,但可能影响性能
  4. 适当冗余可提高查询效率(空间换时间)