数据库
📚 数据库核心概念
数据库定义
数据库是用于长期保存数据、高并发访问数据、快速查询数据的系统,是后端的核心基础设施。
数据库五大特性
- 持久化存储 - 数据写入后不会丢失
- 并发处理能力 - 多用户同时访问,保证数据正确性
- 高效查询 - 通过索引、优化器实现快速检索
- 安全与权限控制 - 精确控制数据访问权限
- 事务一致性 - 通过ACID保证数据完整性
数据库分类
关系型数据库(本课重点)
特点:
代表:
适用:订单管理、用户系统、业务数据
非关系型数据库
特点:
代表:
- Redis(键值)
- MongoDB(文档)
- ElasticSearch(搜索)
适用:缓存、日志、大数据分析
ACID 原则
ACID 是数据库事务的四个核心特性,用于确保数据的可靠性和一致性,尤其在关系型数据库(如 MySQL、PostgreSQL)中至关重要:
A:原子性(Atomicity)
事务被视为一个不可分割的最小单元,事务中的所有操作要么全部成功,要么全部失败回滚,不会停留在中间状态。例如,银行转账必须同时完成扣款和收款,否则回滚到初始状态。
C:一致性(Consistency)
事务执行前后,数据库必须保持一致性状态,即所有数据约束、规则(如唯一性、外键)都得到遵守。例如,转账前后账户总金额应保持不变。
I:隔离性(Isolation)
多个并发事务同时执行时,彼此隔离,互不干扰。数据库通过锁或并发控制机制防止脏读、不可重复读等问题。
D:持久性(Durability)
事务一旦提交,其对数据的修改就是永久性的,即使系统发生故障(如断电)也不会丢失,通常通过持久化存储(如硬盘)实现。
CAP 原则
CAP 理论是分布式系统设计的基础理论,由 Eric Brewer 提出,指出在分布式系统中,以下三个特性无法同时完全满足,最多只能实现其中两个:
C:一致性(Consistency)
在分布式系统的所有节点上,同一时刻读取的数据都是最新的相同版本。例如,用户在任何节点查询数据,都会得到最新的写入结果,否则返回错误。
A:可用性(Availability)
系统始终能够响应请求(不保证数据最新),即使部分节点故障,每个请求都能获得非错误响应。例如,即使数据未同步,系统也返回当前可用的数据。
P:分区容错性(Partition Tolerance)
系统在遇到网络分区(即节点之间因网络问题无法通信)时,仍然能够继续运行。这是分布式系统的基本要求,因为网络分区难以避免。
CAP 的权衡(常见于分布式数据库设计):
CP 系统:保证一致性和分区容错性,牺牲可用性。例如,发生网络分区时,系统可能拒绝写入或读取以确保数据一致。代表:MongoDB(通常配置为 CP)、HBase。
AP 系统:保证可用性和分区容错性,牺牲一致性。例如,发生网络分区时,系统仍可读写,但数据可能临时不一致。代表:Cassandra、DynamoDB。
CA 系统:保证一致性和可用性,牺牲分区容错性。这类系统通常不是真正的分布式系统,如单机关系数据库。
MySQL
数据类型
📊 MySQL数据类型速查
| 类型 |
占用空间 |
范围 |
用途 |
注意事项 |
| INT |
4字节 |
-2^31~2^31-1 |
主键、计数 |
最常用 |
| BIGINT |
8字节 |
-2^63~2^63-1 |
分布式ID |
雪花ID |
| VARCHAR(n) |
可变 |
0~65535字符 |
姓名、标题 |
最推荐 |
| DECIMAL(10,2) |
可变 |
精确小数 |
金额、财务 |
无精度误差 |
| DATETIME |
8字节 |
1000~9999年 |
创建时间 |
最推荐 |
| TIMESTAMP |
4字节 |
1970~2038年 |
自动时间戳 |
2038年问题 |
基础语法
SQL三大组成部分
DDL(数据定义语言)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
CREATE DATABASE school CHARACTER SET utf8mb4;
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE students ADD COLUMN email VARCHAR(100);
|
DML(数据操作语言)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
INSERT INTO students(name, age) VALUES ('张三', 18);
SELECT * FROM students WHERE age > 17;
SELECT * FROM students WHERE name LIKE '%张%';
UPDATE students SET age = 20 WHERE id = 1;
DELETE FROM students WHERE id = 1;
|
DCL(权限控制)
1 2 3 4 5 6 7 8 9 10 11 12
|
CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT ON school.* TO 'username'@'localhost';
REVOKE INSERT ON school.* FROM 'username'@'localhost';
|
事务(Transaction)
ACID原则
- Atomicity(原子性) - 全部成功或全部失败
- Consistency(一致性) - 数据状态合法转移
- Isolation(隔离性) - 事务间互不干扰
- Durability(持久性) - 提交后数据不丢失
事务流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
|
并发问题与隔离级别
| 隔离级别 |
脏读 |
不可重复读 |
幻读 |
MySQL默认 |
| 读未提交 |
✅ |
✅ |
✅ |
❌ |
| 读已提交 |
❌ |
✅ |
✅ |
❌ |
| 可重复读 |
❌ |
❌ |
✅* |
✅ |
| 串行化 |
❌ |
❌ |
❌ |
❌ |
⚠️ 注意:MySQL默认使用**可重复读(Repeatable Read)**级别,是性能与一致性的最佳平衡。
Go操作MySQL
原生SQL方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
dsn := "root:123456@tcp(127.0.0.1:3306)/school?charset=utf8mb4&parseTime=True&loc=Local" db, err := sql.Open("mysql",dsn)
result, err := db.Exec("INSERT INTO students(name, age) VALUES (?, ?)", "王五", 16)
var name string
var age int
err := db.QueryRow("SELECT name, age FROM students WHERE id = ?", 1).Scan(&name, &age)
rows, err := db.Query("SELECT id, name FROM students WHERE age > ?", 15)
defer rows.Close()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name) fmt.Println(id, name)
}
tx, err := db.Begin()
tx.Exec("UPDATE students SET age = age + 1 WHERE id = 1")
tx.Exec("INSERT INTO score_log(student_id, change_amount) VALUES (1, 1)")
err = tx.Commit()
|
Gorm
安装与连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
import ( "gorm.io/driver/mysql" "gorm.io/gorm"
)
dsn := "root:123456@tcp(127.0.0.1:3306)/school?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
定义模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| type Student struct { ID uint gorm:"primaryKey" Name string Age int Grade string CreatedAt time.Time
}
func (Student) TableName() string {
return "students"
}
db.AutoMigrate(&Student{})
|
CRUD操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
student := Student{Name: "张三", Age: 18, Grade: "高三"}
result := db.Create(&student)
fmt.Printf("插入成功,ID: %d\n", student.ID)
var stu Student
db.First(&stu, 1)
db.First(&stu, "name = ?", "张三")
var students []Student
db.Where("age > ?", 17).Find(&students)
db.Model(&Student{}).Where("id = ?", 1).Update("age", 20)
db.Model(&Student{}).Where("id = ?", 1).Updates(Student{Age: 20, Grade: "高三"})
db.Delete(&Student{}, 1)
|
链式查询
1 2 3 4 5 6 7 8 9 10 11 12
| var list []Student
db.Where("age > ?", 16).
Where("grade = ?", "高三").
Order("age desc").
Limit(10).
Find(&list)
|
GORM事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
err := db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&Student{Name: "A"}).Error; err != nil { return err } if err := tx.Create(&Student{Name: "B"}).Error; err != nil { return err } return nil
})
tx := db.Begin()
tx.Create(&Student{Name: "A"})
tx.Model(&Student{}).Where("id=1").Update("age", 20)
tx.Commit()
|
原生SQL vs GORM
| 场景 |
原生SQL |
GORM |
推荐 |
| 简单查询 |
直接灵活 |
简洁易读 |
根据复杂度选择 |
| 复杂联表 |
更可控 |
关联查询 |
原生SQL |
| 快速开发 |
代码量大 |
高效 |
GORM |
| 性能优化 |
极致优化 |
自动优化 |
原生SQL |
| 事务处理 |
手动控制 |
自动封装 |
GORM |
总结
核心要点总结:
- 关系型数据库是业务系统的基石,MySQL是最常用选择
- 事务ACID保证数据一致性,是金融、电商场景的必须品
- GORM框架极大提升开发效率,是Go语言数据库操作的首选
- 原生SQL在复杂查询和性能优化时仍有价值
- 合理选择隔离级别和数据类型是数据库设计的关键
拓展:其他数据库