vault backup: 2026-04-24 23:45:19
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
---
|
||||
tags: [后端, 数据库, SQL, 基础]
|
||||
create time: 2026-04-24 18:41
|
||||
---
|
||||
|
||||
# 数据库基础
|
||||
|
||||
## 概述
|
||||
|
||||
数据库是后端的核心。几乎每个应用都需要持久化数据——用户信息、订单记录、文章内容……关系型数据库(MySQL/PostgreSQL)是后端开发的基石。
|
||||
|
||||
思考题:为什么关系型数据库能统治这么多年?JSON 数据库(如 MongoDB)出现了,为什么我们仍然需要 SQL?
|
||||
|
||||
## 正文
|
||||
|
||||
### 1. 关系模型
|
||||
|
||||
关系数据库用"表"来组织数据,表与表之间通过"关系"(外键)连接。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USERS ||--o{ POSTS : creates
|
||||
USERS {
|
||||
int id PK
|
||||
string username
|
||||
string email
|
||||
datetime created_at
|
||||
}
|
||||
POSTS {
|
||||
int id PK
|
||||
int user_id FK
|
||||
string title
|
||||
string content
|
||||
datetime published_at
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 基础 SQL
|
||||
|
||||
```sql
|
||||
-- 创建表
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
email VARCHAR(100) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 插入数据
|
||||
INSERT INTO users (username, email, password)
|
||||
VALUES ('alice', 'alice@example.com', 'hashed_password');
|
||||
|
||||
-- 查询数据
|
||||
SELECT id, username, email FROM users WHERE id = 1;
|
||||
|
||||
-- 更新数据
|
||||
UPDATE users SET email = 'new@example.com' WHERE id = 1;
|
||||
|
||||
-- 删除数据
|
||||
DELETE FROM users WHERE id = 1;
|
||||
```
|
||||
|
||||
### 3. 多表查询
|
||||
|
||||
```sql
|
||||
-- JOIN 联表查询
|
||||
SELECT u.username, p.title, p.content
|
||||
FROM users u
|
||||
INNER JOIN posts p ON u.id = p.user_id
|
||||
WHERE u.id = 1;
|
||||
|
||||
-- 子查询
|
||||
SELECT * FROM users
|
||||
WHERE id IN (SELECT user_id FROM posts WHERE created_at > '2026-01-01');
|
||||
|
||||
-- 聚合查询
|
||||
SELECT user_id, COUNT(*) as post_count
|
||||
FROM posts
|
||||
GROUP BY user_id
|
||||
HAVING post_count > 10;
|
||||
```
|
||||
|
||||
### 4. 索引 — 数据库性能的命脉
|
||||
|
||||
```sql
|
||||
-- 创建索引
|
||||
CREATE INDEX idx_posts_user_id ON posts(user_id);
|
||||
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
|
||||
|
||||
-- 复合索引
|
||||
CREATE INDEX idx_user_email ON users(email, created_at);
|
||||
```
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[全表扫描 O(n)] -.->|慢| B[数据量增大]
|
||||
C[索引查找 O(log n)] -.->|快| D[数据量增大]
|
||||
```
|
||||
|
||||
> **核心要点:** 索引加速查询但减慢写入。每条写入(INSERT/UPDATE/DELETE)都需要更新索引。不是所有字段都需要索引,通常只给经常用于 WHERE 和 JOIN 的字段加索引。
|
||||
|
||||
> **提问:** B+ 树索引为什么比哈希索引更适合范围查询?
|
||||
|
||||
### 5. 事务(Transaction)— 数据的最后一道防线
|
||||
|
||||
```sql
|
||||
-- 事务保证要么全部成功,要么全部回滚
|
||||
BEGIN;
|
||||
|
||||
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
|
||||
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
|
||||
|
||||
-- 检查是否有错误
|
||||
-- COMMIT; → 全部提交
|
||||
-- ROLLBACK; → 全部回滚
|
||||
```
|
||||
|
||||
ACID 四个特性:
|
||||
|
||||
| 特性 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **A**tomivity(原子性) | 事务要么全做,要么全不做 | 转账时扣款和加款必须同时成功 |
|
||||
| **C**onsistency(一致性) | 事务前后数据保持一致 | 转账前后总金额不变 |
|
||||
| **I**solation(隔离性) | 并发事务互不干扰 | 两个用户同时转账不会出问题 |
|
||||
| **D**urability(持久性) | 提交后数据永久保存 | 断电后数据不会丢失 |
|
||||
|
||||
> **思考:** 如果转账过程中服务器在两条 UPDATE 之间崩溃,会发生什么?ACID 的原子性如何避免这个问题?
|
||||
|
||||
### 6. Go 操作数据库示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/lib/pq" // PostgreSQL 驱动
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int
|
||||
Username string
|
||||
Email string
|
||||
}
|
||||
|
||||
func getUser(db *sql.DB, id int) (*User, error) {
|
||||
var user User
|
||||
err := db.QueryRow("SELECT id, username, email FROM users WHERE id = $1", id).
|
||||
Scan(&user.ID, &user.Username, &user.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// 事务示例
|
||||
func transfer(db *sql.DB, fromID, toID, amount int) error {
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback() // 出错时自动回滚
|
||||
|
||||
_, err = tx.Exec("UPDATE accounts SET balance = balance - $1 WHERE user_id = $2", amount, fromID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec("UPDATE accounts SET balance = balance + $1 WHERE user_id = $2", amount, toID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
```
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[API 设计]] — API 需要操作数据库
|
||||
- [[Go 后端基础]] — Go 连接数据库的实践
|
||||
- [[30.areas/finance/Investment lessons/2024.Current trading lessons.md]]
|
||||
Reference in New Issue
Block a user