数据库分为关系型数据库和非关系型数据库
常用的关系型数据库有mysql、oracle、sql server
常用的非关系型数据库有mongodb、redis
什么是mysql?
了解mysql,首先要知道关系型数据库。
关系型数据库是信息的集合,它以预定义的关系组织数据,数据存储在一个或多个由列和行构成的表(或“关系”)中,用户可以轻松查看和理解不同数据结构之间的关系。关系是不同表之间的逻辑连接,根据这些表之间的交互建立。
这样笼统的定义大家可能不清楚,我们细分为几个点来讲解:
- 基本组成: 数据库、表、行、列
-
预定义结构:高度依赖二维表格,每个表格里的字段都是预先定义好的,以客户表为例,需要预先定义好字段类型
id、name、phone、address-
+----+---------+-------------+-----------+ | id | name | phone | address | +----+---------+-------------+-----------+ | 1 | 客户1 | 13127354603 | 深圳市 | | 2 | 客户2 | 12346253843 | 广州市 | | 3 | 客户3 | 13123423424 | 佛山市 | +----+---------+-------------+-----------+
-
-
表与表之间有联结关系:以客户表和订单表为例,客户表跟订单表是通过
foreign key: client_id关联起来的-
+------+-----------+-----------+---------------+--------+ | id | client_id | goods | issuance_date | status | +------+-----------+-----------+---------------+--------+ | 1001 | 1 | 电脑 | 2022-10-12 | 1 | | 1002 | 2 | 笔记本 | 2022-10-20 | 2 | | 1003 | 3 | 手机 | 2022-11-11 | 2 | +------+-----------+-----------+---------------+--------+
-
- SQL 语句:通用的sql语言,对数据表的建立和操作都依赖sql语句
CREATE TABLE IF NOT EXISTS orders(
id int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
client_id int UNSIGNED NOT NULL COMMENT '关联客户id',
goods varchar(100) NOT NULL COMMENT '货物',
issuance_date Date NOT NULL COMMENT '发货日期',
status int UNSIGNED NOT NULL COMMENT '订单状态',
FOREIGN KEY (client_id) REFERENCES client (id)
) ENGINE = InnoDB CHARSET = utf8;
insert into orders (client_id, goods, issuance_date, status) values (3, '手机', '2022-11-11', 2);
什么是mongodb?
mongodb是非关系型数据库,也叫NoSql数据库。主要指那些非关系型的、分布式的,且一般不保证ACID的数据存储系统。NoSQL提出了另一种理念,以键值来存储,且结构不稳定,每一个元组都可以有不一样的字段,这种就不会局限于固定的结构,可以减少一些时间和空间的开销。使用这种方式,为了获取用户的不同信息,不需要像关系型数据库中,需要进行多表查询。仅仅需要根据key来取出对应的value值即可。
- 基本组成:数据库、集合、文档、域
- 动态结构:在sql中,必须定义好地段和表结构之后,才能够添加数据,例如定义表的主键、索引、外键等。在Nosql数据库中,数据可以在任何时候任何地方添加。不需要预先定义,也不需要预先创建表格,字段也不需要保持一致。
{
"_id" : ObjectId("6356459b0ad81bc66bfd4b6c"),
"client_id" : "1",
"goods" : "电脑",
"issuance_date" : "2022-10-12",
"status" : 1
}
{
"_id" : ObjectId("635751d00ad81bc66bfd4b6e"),
"client_id" : "1",
"goods" : "电脑",
"issuance_date" : "2022-10-12",
"update_date" : "2022-12-12"
}
- NoSql: Not Only Sql,不像传统的Sql语言,采用结构化的查询语句
db.orders.insert({
client_id: '1',
goods: '电脑',
issuance_date: '2022-10-12',
status: 1
})
能力对比
| 对比 | mysql | mongodb |
|---|---|---|
| 数据结构 | 预定义对象数组 | json |
| 动态schema | 不支持,可以把字段类型设置为JSON来代替 | 支持 |
| 增 | INSERT INTO orders( client_id, goods, issuance_date, status) VALUES( 3, '货物', '2022-12-12', 3); | db.orders.insert({ client_id: '1', goods: '电脑', }) |
| 删 | drop table orders; | db.collection.drop() |
| 改 | update orders set goods='苹果' where id = 1004; | db.orders.update({goods: "电脑"},{ $set:{title: "手机"} }) |
| 查 | select * from orders; | db.orders.find().pretty() |
| 语句 | 语法为传统的sql语法,对于新人上手有一定的心智负担。可以通过封装第三方库比如sequelize、typeorm来支持,但是orm库本身也有自己的api语法,而且对于联表查询或者复杂语句,支持起来也需要熟练相关api,这对于新人入手无疑也是有一定的心智负担的。 | 语法更加接近面向对象编程,对于没接触过传统数据库语法的,易于上手,没有心智负担 |
| 可视化工具 | MySQL Workbench、Sequel Pro、HeidiSQL、Navicat | Rockmongo、Navicat for MongoDB、NoSQLBooster for MongoDB |
| 引擎 | 常用的有InnoDB、MyISAM、MEMORY | 常用的有mmapv1、inMemory、WiredTiger |
| 事务 | 事务是一种处理机制,用来管理数据语句必须成批的执行,以保证数据库不会包含不完整的执行结果。通俗点说,事务包含的数据语句要么完整执行,要么不执行。如果执行不完整或者发生错误,则进行回退。事务的特性:原子性、一致性、隔离型、持久性。事务的常见操作:事务(transaction)、回退(rollback)、提交(commit)、保留点(savepoint) | |
| 事务支持 | 只有InnoDB引擎支持BEGIN; DELETE FROM client WHERE id = 1; DELETE FROM orders WHERE client_id = 1; COMMIT; | 3.6版本开始支持const session = db.getMongo().startSession(); session.startTransaction({readConcern: { level: 'majority' },writeConcern: { w: 'majority' }}); const client = session.getDatabase('test').getCollection('client'); const orders = session.getDatabase('test').getCollection('orders'); client.remove({'id': 1}); orders.remove({'client_id': 1}); session.commitTransaction(); |
| 复杂查询 | 支持INNER JOIN(内连接,或等值连接)、LEFT JOIN(左连接)、RIGHT JOIN(右连接)、GROUP BY、SUM、AVG等 | 通过聚合操作aggregate可以使用group、avg等 |
| 锁 | 概念:锁是计算机用以协调多个进程间并发访问同一共享资源的一种机制。要解决的是并发请求下资源分配的问题,对于数据库来说,就是并发的读写。类型:读的共享锁(S)和用于写的排它锁(X),也叫悲观并发控制。读的意向共享锁(IS)和用于写的排它锁(X),也叫乐观并发控制。粒度:由大到小划分为全局锁、库锁、表锁、行锁、页锁、文档锁,粒度越小,越不易阻塞。比如数据库只支持表锁,将导致在锁情况下,其它资源无法对该表进入操作。如果可以支持行锁,那么其他资源对该表还是可以操作的,只是无法操作改行。死锁:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。比如有个A、B两个请求都是对表C、D进行写入操作,A请求先对C加锁,还未对D进行加锁,而此时B请求却优先对D进行加锁,这样就导致A请求无法操作D,B请求无法操作C,进入了死循环。 | |
| 锁支持 | 默认支持表锁。InnoDB支持行锁。MyISAM额外支持页锁。 | 2.2之前只有全局锁。2.2之后开始有库锁和表锁。3.0之后WiredTiger支持文档锁。 |
| 自动分片 | 分片是一种将大型数据集分布在不同数据集合中的方法。在这里,用户可以选择一个分片键(具有单个或多个副本的主键)来确定集合中的数据分布,并将数据拆分为跨分片的不同范围。每个分片都充当单独的数据库,使用其他分片形成一个数据库有助于负载平衡并执行复杂的查询 | |
| 自动分片支持 | 可以通过分片框架MySQL Fabric实现 | 天然支持通过分片进行水平扩展 |
| 性能 | 从理论上讲,同等条件下,MongoDB 接收任何数据都比 MySQL 快,而且能接收的数据量也比 MySQL 多。因为Mongo使用的内存映射技术,用空间换取时间, 写入数据时候只要在内存里完成就可以返回给应用程序,这样并发量自然就很高,而保存到硬件的操作则在后台异步完成。但如果涉及到联表查询、分组等复杂语句以及大量用户访问时,对内存的要求也高,加上锁的影响,虽然mongodb也能支持,但这时候的访问效率可能反倒会不如mysql。不过,性能问题总归要看场景而言,不能一概而论。 | |
| 应用场景 | - 如果你的业务对于存储要求很高、存储量大、并且业务结构有很大的不确定性,那么mongodb是一个很好的选择,比如日志系统、流水系统、云服务系统。- 如果你的业务需要支持复杂的事务查询、对ACID要求很高,那么结构化的mysql能够为你提供强大的能力支持,比如银行资金系统、火车票订单系统。- 不过,大部分情况下,并不需要选择,常用的后台管理系统、记账系统等用户量不高、只有存储需求的场景,mongodb和mysql都是可以满足需求的。- 另外,mysql和mongodb也经常一起使用,比如把mysql作为主库,由于其本身结构化特点,对于后期维护的技术债成本会比较低,而mongodb天然的面向对象设计,作为缓存数据库,也是可以带来很大的收益的。 |
补充
Redis也是常用的数据库,它跟mongodb一样,也是NoSql的一种,但它不是文档型的,而是基于键值对的。redis的数据是存储在内存中的,所以其优点很明显,读写性能极高,缺点也很明显,使用空间很小,所以一般的使用场景都是用来存放用户信息这类读写频率高、数据量不大的场景。