PostgreSQL安装与ACID介绍

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

这一阶段的核心目标是用最短时间、最顺畅的方式让你拥有一个可以动手实践的 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 复制代码
    <BASH>
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  3. 使用 Homebrew 安装 PostgreSQL:

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

    sql 复制代码
    <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 复制代码
<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/address : localhost
      • Port : 5432
      • Maintenance database : postgres (默认数据库)
      • Username : postgres (Windows/图形化安装器) 或你的系统用户名(macOS Homebrew安装)
      • Password: 你安装时设置的密码(如果是Homebrew无密码,则留空)
    5. 点击 "Save"。如果一切顺利,左侧就能展开看到你的数据库服务器和其中的数据库了。

pgAdmin 界面概览

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

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

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

如何启动 psql
  • Windows

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

    • 打开终端。

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

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

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

BASH 复制代码
# 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 语句,以分号 (;) 结尾,然后按回车执行。

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 表,包含 id, title, author, price 字段。
      • 插入 2-3 条图书数据。
      • 执行一次查询,显示所有图书。
  4. 理解概念

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

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

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

ACID 定义

TEXT 复制代码
A - Atomicity     原子性
C - Consistency    一致性
I - Isolation      隔离性
D - Durability     持久性

1. 原子性 (Atomicity)

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

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

例子: 银行转账

SQL 复制代码
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)

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

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

约束类型:

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

例子:

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

3. 隔离性 (Isolation)

"并发事务互不干扰"

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

隔离级别:

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

1. 读未提交 (READ UNCOMMITTED)

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

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

SQL 复制代码
-- 会话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 默认级别:只能读取已提交的数据

SQL 复制代码
-- 演示:两个转账同时进行
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;

但有问题:不可重复读

SQL 复制代码
-- 会话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)

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

SQL 复制代码
-- 会话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)

SQL 复制代码
-- 会话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;

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

SQL 复制代码
-- 会话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)

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

SQL 复制代码
-- 经典的"丢失更新"问题演示
-- 会话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)

"一旦提交,永不丢失"

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

实现机制:

TEXT 复制代码
┌─────────────────────────────────────┐
│      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实现:

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实现:

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 复制代码
<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)
);

三、视觉化对比

一对一关系:

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

一对多关系:

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

多对多关系:

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

四、实际应用建议

选择建议:

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

关系设计技巧:

  1. 分析业务需求时,先确定实体间的真实关系
  2. 多对多关系一定需要中间表
  3. 外键约束保证数据完整性,但可能影响性能
  4. 适当冗余可提高查询效率(空间换时间)
相关推荐
AI人工智能+电脑小能手7 分钟前
【大白话说Java面试题 第89题】【Mysql篇】第19题:Hash 索引和 B+ 树索引的区别?它们在使用方面的区别?
java·数据库·mysql·面试·哈希算法
我是一颗柠檬9 分钟前
【Java后端技术亮点】动态路由权限(按钮级权限),细粒度控制到按钮级别
java·开发语言·后端·状态模式
前端Hardy16 分钟前
CSS 动画真的比 JS 快?Josh Comeau 做了组实验,结果跟直觉不一样
前端·javascript·后端
Front思16 分钟前
调取支付宝支付正式环境不可以唤起来,但是沙箱可以
后端
foggyprojects23 分钟前
AI 生成 SQL 模板以后,为什么还需要固定 helper 规则
后端
明天一点23 分钟前
Cloudflare 通知转发钉钉机器人
前端·后端
前端Hardy24 分钟前
前端日历组件,要变天了?Schedule-X v4.6 彻底杀疯了
前端·javascript·后端
Oo_行者_oO31 分钟前
微服务 Feign 从“万能公共服务”到“业务客户端”
后端·架构
wei_shuo32 分钟前
别再踩坑了!KingbaseES 存储过程与触发器开发避坑实录
后端
元宝骑士33 分钟前
MySQL 实战:跨表排序 + 指定类型置顶四种写法
后端·mysql