myserver-helloword-database
数据库简介
- 定义:数据库是⽤于存储、管理和处理数据的系统。它允许存储⼤量信息,⽀持数据的有效组织、存储、访问和更新。
- 作⽤:
- 数据存储:可持久存储各种数据,如⽂本、数字、图⽚等。
- 数据管理:提供管理数据的功能,如数据的增加、删除、修改和查询。
- 数据处理:⽀持对数据进⾏各种操作,以满⾜特定的业务需求。
- 数据查询:允许通过SQL(结构化查询语⾔)等查询语⾔进⾏⾼效数据检索。
- 应⽤场景:
- 商业数据存储、⽹站数据管理、移动应⽤数据处理等。
- 相关概念:
- 数据库管理系统(Database Management System,DBMS)是⽤于定义、创建、维护和控制据库的软件系统。它提供了数据的访问、管理和保护等功能,常⻅的 DBMS 包括 MySQL、PostgreSQL、SQLite 等
- 关系型数据库(Relational Database)是基于关系模型的数据库,数据以表格形式存储,表与表之间通过键进⾏关联。关系型数据库⽀持 SQL(结构化查询语⾔)进⾏数据操作。
- SQL(Structured Query Language)是⽤于管理和查询关系型数据库的标准语⾔。它包括数据定义语⾔(DDL)、数据操纵语⾔(DML)、数据控制语⾔(DCL)和数据查询语⾔(DQL)等部分。
DBMS(数据库管理系统)和数据库对⽐
数据库(Database)
数据库是实际存储数据的集合,可以理解为⼀种容器,⽤于存放结构化的信息。数据库包括表、记
录、列等各种数据对象,通过这些对象来组织和存储信息。
- 组成:数据库中的数据通常是按某种结构存储的,例如在关系型数据库中,数据按表(表由⾏和列组成)的形式存储。
- 作⽤:数据库本⾝不具备管理、控制数据的功能,它只是数据的存储空间,数据存储的格式和内容由具体的需求决定。
2. 数据库管理系统(DBMS)
数据库管理系统(DBMS)是管理、控制和访问数据库的⼯具或软件系统,它提供了⼀组功能来实现对
数据库中的数据进⾏⾼效、安全的存储、检索、修改和删除。
- 组成:DBMS 包含⼀系列软件组件,例如查询引擎、存储引擎、⽇志管理、事务管理等。
- 作⽤:DBMS 负责数据的存储、更新、查询、并发控制、数据安全、数据备份和恢复等任务。它提供了⼀组接⼝,使得⽤⼾或应⽤程序可以通过查询语⾔(如 SQL)来操作数据库。
ACID
ACID 是数据库事务的四个基本特性,⽤于确保数据在并发操作和系统故障时的正确性和⼀致性。
ACID 是 原⼦性(Atomicity)、⼀致性(Consistency)、隔离性(Isolation) 和 持久性(Durability)的缩写。
- 原⼦性(Atomicity)
原⼦性确保事务中的所有操作要么全部执⾏,要么全部不执⾏,不允许部分完成。例如,银⾏转账操作必须同时扣除⼀个账⼾的余额并增加另⼀个账⼾的余额,不能只执⾏其中⼀个操作。
• 实现⽅法:数据库通过⽇志(log)或回滚机制来实现原⼦性。⽇志记录事务的每⼀个操作,若事务失败,数据库会使⽤⽇志回滚到事务开始前的状态。 - ⼀致性(Consistency)
⼀致性保证数据库在事务完成前后都处于⼀种合法的状态,即所有约束(如主键、外键、唯⼀性约束等)在事务执⾏前后都有效。例如,⼀个银⾏账⼾的余额不能变成负数。
- 实现⽅法:数据库在每次事务执⾏时,会⾃动检查并保持所有约束的完整性,确保数据不会违反这些规则。若违反约束,事务会被回滚。
- 隔离性(Isolation)
隔离性确保多个事务同时执⾏时不会互相⼲扰。⼀个事务的中间状态对其他事务是不可⻅的,直到该事务提交。隔离性防⽌了并发事务间的数据冲突。
- 隔离级别:
- 未提交读(Read Uncommitted):事务可以看到其他未提交事务的数据,容易引发脏读。
- 已提交读(Read Committed):事务只能看到已提交的数据,避免了脏读。
- 可重复读(Repeatable Read):保证在同⼀事务中多次读取的数据⼀致,防⽌不可重复读。
- 序列化(Serializable):最⾼隔离级别,所有事务串⾏执⾏,避免并发问题,但性能较低。
- 实现⽅法:数据库通常通过锁机制或多版本并发控制(MVCC)来实现隔离性。锁定数据可以防⽌其他事务在未提交时访问或修改数据,⽽ MVCC 通过保存数据的多个版本提供更⾼效的并发⽀持。
- 持久性(Durability)
持久性保证事务⼀旦提交,数据就会永久保存在数据库中,即使系统故障或重启,已提交的数据也不会丢失。
- 实现⽅法:数据库使⽤写前⽇志(WAL)和数据持久化机制来确保持久性。在事务提交前,数据库会将所有修改写⼊⽇志并保存到磁盘,确保数据的永久性。
总结 - 原⼦性:事务的操作要么全部完成,要么全部不执⾏。
- ⼀致性:事务的执⾏不能破坏数据的完整性约束。
- 隔离性:并发事务间互不⼲扰,避免数据冲突。
- 持久性:事务提交后的数据永久保存在数据库中。
ACID 特性确保了数据库系统的可靠性和⼀致性,使得数据库在并发和故障情况下仍能保持数据的正确性。
MySQL
MySQL的特点
- 开源免费:MySQL 采⽤了开放源代码许可证,可以免费使⽤、修改和分发,且具备付费商业版本,提供更⾼的⽀持。
- 跨平台:⽀持多种操作系统,包括 Windows、Linux、macOS 等,可以在不同平台之间迁移。
- 性能⾼效:MySQL 对查询和数据处理进⾏了优化,提供快速的读写操作,适⽤于中⼩型应⽤和Web 服务。
- ⽀持多⽤⼾并发访问:提供强⼤的并发性,可以处理多个⽤⼾的同时访问和操作。
- 数据安全性:提供访问控制、密码加密、数据备份等安全机制,确保数据的完整性和安全性。
- 丰富的存储引擎:⽀持多种存储引擎(如 InnoDB、MyISAM),可以根据需求选择合适的引擎来优化性能。
MySQL的缺陷
- 功能限制:相较于其他⾼级数据库(如 PostgreSQL、Oracle),MySQL 在某些⾼级功能(如触发器、存储过程、复杂查询)上较弱。
- 事务处理不如其他数据库:尽管 MySQL ⽀持事务处理(主要依赖 InnoDB 引擎),但在某些场景下,事务的隔离性和⼀致性可能不如其他数据库(如 PostgreSQL)。
- ⼤数据量性能下降:当数据量⾮常⼤或查询变得复杂时,MySQL 的性能可能会受到影响,并需要专⻔的优化。
- 有限的 ACID ⽀持:MySQL 对 ACID 特性(原⼦性、⼀致性、隔离性、持久性)的⽀持依赖于所选存储引擎,⽽部分引擎可能不完全满⾜ ACID 要求。
- 扩展性较弱:MySQL 对于集群和分布式架构的⽀持有限,需要借助第三⽅⼯具或插件来实现分布式数据存储和⾼可⽤性。
总结
MySQL 是⼀种开源、跨平台、性能⾼效的关系型数据库管理系统,适⽤于中⼩型应⽤、Web 开发等场景。尽管在事务处理和⼤数据量性能上有⼀定局限,但通过合理的优化和配置,MySQL 依然是⼀款⼴泛使⽤的数据库解决⽅案。
SQLite数据库
- SQLite概述:
- 嵌⼊式数据库:SQLite是⼀种轻量级的数据库,它不像传统数据库那样需要单独的服务器。SQLite的数据库是⼀个⽂件,可以直接集成到应⽤程序中。
- 主要特点:
- ⽆需服务器:不需要配置和维护独⽴的数据库服务器,数据库以⽂件形式存在于应⽤程序中。
- 跨平台:⽀持多种操作系统,包括Windows、Linux、Mac OS等。
- ⾃给⾃⾜:不需要依赖外部的数据库管理系统。
- ⼩巧灵活:占⽤资源少,适⽤于资源受限的环境。
- 易于操作:通过SQL语⾔进⾏数据库操作,简单易学。
- 优势:
- 适合于轻量级应⽤,尤其是对服务器依赖要求低的场景。
- 易于部署和维护,降低了应⽤的复杂性和成本。
- 应⽤场景:
- 移动应⽤:如 Android、iOS 应⽤的数据存储。
- 嵌⼊式系统:在硬件资源有限的设备上使⽤。
- ⼩型⽹站:适⽤于访问量较⼩的⽹站或内部⼯具。
- 测试和开发:快速搭建数据库环境,进⾏功能验证。
基本架构:
- 核⼼库(Core Library):
- SQLite的核⼼库包括SQL解析器、查询优化器、存储引擎等核⼼组件,⽤于处理SQL语句的解析、优化和执⾏。
- 核⼼库负责管理数据库⽂件、表格、索引等数据结构。
- 存储引擎:
- SQLite使⽤B-tree数据结构来管理表格和索引的数据存储。
- B-tree是⼀种⾼效的数据结构,⽀持快速的数据查找、插⼊和删除操作。
- SQLite⽀持多种存储引擎,例如磁盘存储引擎、内存存储引擎等,允许在不同场景下进⾏选
择。
- 虚拟机(Virtual Machine):
- SQLite使⽤虚拟机执⾏SQL语句。
- SQL语句⾸先由SQL解析器解析为抽象语法树(AST),然后由虚拟机执⾏。
- 虚拟机可以执⾏SQL查询、插⼊、更新和删除操作。
- ⽂件系统接⼝:
- SQLite需要与底层⽂件系统交互,读取和写⼊数据库⽂件。
- 不同平台的⽂件系统接⼝被封装成操作系统相关的代码,以保证跨平台兼容性。
- 外部接⼝:
- SQLite提供了⼀系列的C语⾔API,以便应⽤程序与数据库进⾏交互。
- 应⽤程序可以通过API执⾏SQL查询、事务管理、数据读写等操作。
- 内存管理:
- SQLite需要有效地管理内存资源,包括分配、释放和缓存数据。
- 内存管理器负责管理数据库的内存使⽤。
- 线程安全:
- SQLite可以在多线程环境中使⽤,但需要注意线程安全性问题。
- 在多线程应⽤中,SQLite通常需要使⽤互斥锁(Mutex)来确保数据的⼀致性和安全性。
SQL语法⼊⻔
SELECT语句
- ⽤途:⽤于从表中检索数据。
1
2SELECT 列名1, 列名2, ...
FROM 表名; - ⽰例:
1
SELECT 姓名, 年龄 FROM ⽤⼾;
WHERE⼦句
- ⽤途:⽤于过滤满⾜特定条件的记录。
1
2
3SELECT 列名1, 列名2, ...
FROM 表名
WHERE 条件; - ⽰例:
1
SELECT 姓名, 年龄 FROM ⽤⼾ WHERE 年龄 > 18;
INSERT INTO语句
- ⽤途:⽤于过滤满⾜特定条件的记录。
1
2INSERT INTO 表名 (列名1, 列名2, ...)
VALUES (值1, 值2, ...); - ⽰例:
1
INSERT INTO ⽤⼾ (姓名, 年龄) VALUES ('李四', 25);
UPDATE语句
- ⽤途:⽤于更新表中的数据。
1
2
3UPDATE 表名
SET 列名1 = 值1, 列名2 = 值2, ...
WHERE 条件; - ⽰例:
1
UPDATE ⽤⼾ SET 年龄 = 26 WHERE 姓名 = '李四';
DELETE语句
- ⽤途:⽤于删除表中的记录。
1
DELETE FROM 表名 WHERE 条件;
- ⽰例:
1
DELETE FROM ⽤⼾ WHERE 姓名 = '李四';
CREATE TABLE语句
- ⽤途:⽤于创建新表。
1
2
3
4
5CREATE TABLE 表名 (
列名1 数据类型,
列名2 数据类型,
...
); - ⽰例:
1
2
3
4
5CREATE TABLE ⽤⼾ (
id INT AUTO_INCREMENT PRIMARY KEY,
姓名 VARCHAR(100),
年龄 INT
);
ALTER TABLE语句(添加、删除、修改列)
- ⽤途:⽤于修改已存在的表。
1
2
3
4
5
6
7
8ALTER TABLE 表名
ADD 列名 数据类型;
ALTER TABLE 表名
DROP COLUMN 列名;
ALTER TABLE 表名
MODIFY COLUMN 列名 数据类型; - ⽰例:
1
2ALTER TABLE ⽤⼾ ADD 邮箱 VARCHAR(255);
);
特殊符号
- *(星号):
- 在SQL查询语句中, * 是⼀个通配符,⽤于表⽰选择表中的所有列。例如,在 SELECT * FROM table_name; 中, * 意味着从指定的table_name表中选取所有的字段数据。
- % (百分号):
- 在SQL LIKE操作符中, % 是通配符,代表零个或多个任意字符。例如: SELECT column FROM table WHERE column LIKE ‘%pattern%’; 会查找column列中包含”pattern”任何位置的⾏。
- 在⼀些数据库系统(如MySQL)的模式匹配函数中, % 也⽤于模糊搜索。
- _ (下划线):
- 与 % 类似,但在LIKE操作符中, _ 代表单个任意字符。例如: SELECT column FROM table WHERE column LIKE ‘prefix___’; 将查找以”prefix”开头且后⾯跟三个任意字符的⾏。
- \ (反斜杠):
- 在SQL字符串和正则表达式中,反斜杠 \ ⽤来转义特殊字符。如果要匹配⼀个实际的反斜杠字符,需要写两个反斜杠 \\ ,因为在SQL字符串字⾯量中,反斜杠本⾝也是⼀个转义字符。
- 连接运算符:
- = 和 = 曾经在某些旧版数据库系统中⽤于表⽰外连接操作,但不是SQL标准的⼀部分。在现代SQL中,使⽤ LEFT JOIN , RIGHT JOIN 或 FULL OUTER JOIN 来进⾏外连接操
- 作。如: SELECT * FROM table1 LEFT JOIN table2 ON table1.id *= table2.id; 这样的写法在⾮标准SQL中可能表⽰左连接,但在遵循ANSI SQL标准的系统中应写作 … LEFT JOIN … ON table1.id = table2.id;
- 其他符号和运算符:
- < > <= >= <> != AND OR NOT IN BETWEEN 等是⽐较和逻辑运算符,⽤于在WHERE⼦句和其他条件表达式中构建复杂的过滤条件。
SQL注入及其防⽌
常⻅的SQL注⼊⽅法:
直接注⼊
- 概念:攻击者在应⽤程序的输⼊字段中插⼊恶意SQL代码,利⽤不安全的字符串拼接或预编译语句处理机制,绕过验证并执⾏⾮预期的数据库操作。
- 例⼦:假设⽹站登录表单存在漏洞,攻击者可以在⽤⼾名输⼊框内输⼊ admin’ OR ‘1’=’1 。系统⽣成的SQL查询可能变为 SELECT * FROM users WHERE username = ‘admin’OR ‘1’=’1’ AND password = ‘…’; 。由于条件 ‘1’=’1’ 永远为真,这将导致验证逻辑失效,使得攻击者即使不知道正确的密码也能成功登录。
1
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';
注释注⼊
- 概念:攻击者通过在⽤⼾提供的输⼊中添加SQL注释符号(如 – 或 /* */ ),使得原始SQL语句的剩余部分被数据库忽略执⾏。
- 例⼦:在登录场景中,攻击者在⽤⼾名字段输⼊ admin’– ,这样后续的密码验证部分将被视为注释内容,攻击者可能因此绕过密码验证环节,即使没有提供正确密码也能登录。
1
SELECT * FROM users WHERE username = ''; DROP TABLE users; --' AND password ='...';
联合查询注⼊
- 概念:攻击者利⽤ UNION 操作符结合多个SELECT语句,从⽽从数据库中获取原本不应访问的数据记录。
- 例⼦:攻击者尝试在输⼊域中输⼊ 1 UNION SELECT username, password FROM users ,这样可以将查询结果扩展⾄包含所有⽤⼾的⽤⼾名和密码信息。⼦查询注⼊
- 概念:攻击者嵌⼊⼀个或多个额外的SELECT⼦查询到原SQL语句内部,以实现对数据库未经授权的读取或其他操作。
- 例⼦:攻击者提交如下输⼊: 1; SELECT * FROM users WHERE username = ‘admin’ ,这种情况下,数据库可能会连续执⾏两个独⽴的查询,第⼆个查询可能暴露管理员账⼾的相关数据。
防⽌SQL注⼊的⽅法:
- 预编译语句(参数化查询)
- 实践⽅法:在构建SQL语句时,预先定义好SQL命令的结构,并将⽤⼾提供的数据作为参数传⼊,⽽不是直接嵌⼊到字符串中。数据库系统会识别并正确处理这些参数,确保它们不会被解释为SQL代码。
- 例⼦:使⽤Java和JDBC执⾏预编译查询时,可以先 PreparedStatement 对象来设置SQL模板,例如 SELECT * FROM users WHERE username = ? AND password = ?; ,然后通过 .setString() ⽅法绑定实际参数值,这样即使参数中包含特殊字符如单引号 ‘ ,也不会被执⾏。
- ORM框架
- 原理与应⽤:通过使⽤Hibernate、Entity Framework等ORM框架,开发者可以通过操作对象的⽅式来间接操作数据库,ORM框架内部通常会对参数进⾏⾃动转义或使⽤参数化查询,从⽽避免SQL注⼊⻛险。
- 例⼦:在.NET环境中,利⽤Entity Framework执⾏⼀个登录验证时,可以声明⼀个LINQ查询表达式,如 var user = context.Users.FirstOrDefault(u => u.Username == userInput && u.Password == passwordInput); ,这⾥的输⼊会被框架安全地处
- 输⼊验证
- 实施步骤:对所有⽤⼾提交的数据进⾏严格的格式检查和类型校验,确保输⼊内容符合预期的业务逻辑和数据格式要求。
- 例⼦:对于⼿机号码字段,应确保输⼊的是有效的11位数字串;在接收⽇期输⼊时,应检验其是否符合YYYY-MM-DD格式,⽆效格式则拒绝接收并提⽰错误。
- 最⼩权限原则
- 策略描述:应⽤程序连接数据库所使⽤的账⼾应当仅拥有完成当前任务所需的最⼩⼦集权限,⽐如只读访问特定表,⽽⾮整个数据库的所有权限,更不能使⽤超级管理员账号。
- 实例说明:假设某个模块只需要读取users表的信息,则该模块对应的数据库连接账⼾只需赋予SELECT权限于users表,⽽⽆需UPDATE、DELETE或其他表的任何权限。
- 禁⽌直接拼接SQL
- 安全实践:绝对避免将⽤⼾输⼊直接插⼊到SQL字符串中形成新的查询,因为这种做法极易受到SQL注⼊攻击。
- 反例警⽰:不安全的做法是这样的: String sql = “SELECT * FROM users WHERE username = ‘“ + userInput + “‘“; ,正确的做法是采⽤上述提及的预编译语句或者参数化查询。
- 使⽤安全函数
- 应急措施:对于那些不⽀持预编译语句或参数化查询的⽼旧数据库接⼝,可使⽤数据库⾃⾝提供的安全函数对特殊字符进⾏转义以防⽌SQL注⼊。
- ⽰例代码:在MySQL中,可以调⽤ mysqli_real_escape_string() 函数对⽤⼾输⼊的内容进⾏转义,⽽在PDO中,则可以使⽤ quote() ⽅法对字符串进⾏包裹,确保其在SQL语句中的安全性。例如:
1
2$usernameEscaped = $pdo->quote($userInput);
$sql = "SELECT * FROM users WHERE username = $usernameEscaped";
防注⼊代码
1 | // 准备SQL语句,预编译以防⽌SQL注⼊攻击 |
Database.h
1 |
|
myserver.cpp
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ysmmm的快乐小屋!