第五章 存储Node程序中的数据
一、无服务器的数据存储:内存存储和基于文件的存储
1、内存存储
- 使用场景:存放少量经常使用的数据(如跟踪记录最近一次重启服务器后页面访问次数),服务器和程
序重启后数据就丢了。
2、基于文件的存储 fs
- 使用场景:保存程序的配置信息,数据的持久化保存,在程序和服务器重启后依然有效。
- 并发问题:两个用户可能会同时加载相同的文件进行修改。保存一个版本会覆盖另外一个,导致其中某个用户的修改丢失。对于多用户程序而言,数据库管理系统是更合理的选择,因为它们就是为应对并发问题而生的。
二、关系型数据库管理系统 ——MySQL和PostgreSQL
关系数据库管理系统(RDBMS)可以存储复杂的信息,并且查询起来很容易。
1、MySQL
- 使用步骤
(1)安装MySQL Node模块
npm install mysql
三、NoSQL 数据库—— Redis 和 MongoDB
很多NoSQL数据库把性能放在了第一位,对于实时分析或消息传递而言,NoSQL数据库可能是更好的选择。NoSQL数据库通常也不需要预先定义数据schema,对于那种要把数据存储在层次结构中,但层次结构却会发生变化的程序而言,这很有帮助。
1、Redis
-
适应场景:处理那些不需要长期访问的简单数据存储,比如短信和游戏中的数据。
-
特点:
(1)Redis把数据存在RAM中,并在磁盘中记录数据的变化。这样做的缺点是它的存储空间有限,但好处 是数据操作非常快。如果Redis服务器崩溃,RAM中的内容丢了,可以用磁盘中的日志恢复数据。
(2)提供了实用的原语命令集,可以处理几种数据结构。哈希表、链表、键/值对(作为简单的变量使用)、集合(set)
- 使用步骤
(1)安装node_redis模块
npm install redis
(2)连接Redis服务器
连接到运行在同一主机,默认TCP/IP端口上的Redis服务器。你创建的这个Redis 客户端继承了EventEmitter的行为,当客户端跟Redis服务器通信出现问题时,它会抛出一个 error事件。
var redis = require('redis');
var client = redis.createClient(6379, '127.0.0.1');
client.on('error', function (err) {
console.log('Error ' + err);
});
(3)操作Redis中的数据
// 存储和获取键/值对
client.set('color', 'red', redis.print);
client.get('color', function(err, value) {
if (err) throw err;
console.log('Got: ' + value);
});
2、MongoDB
MongoDB数据库把文档存在集合(collection)中。它们不需要相同的schema,每个文档都可以有不同的schema。 这使得MongoDB比传统的RDBMS更灵活,因为你不用为预先定义schema而操心。
- 使用步骤
(1)安装MongoDB
npm install mongodb
(2)连接MongoDB
var mongodb = require('mongodb');
var server = new mongodb.Server('127.0.0.1', 27017, {});
var client = new mongodb.Db('mydatabase', server, {w: 1});
(3)访问MongoDB集合
client.open(function(err) {
if (err) throw err;
client.collection('test_insert', function(err, collection) {
if (err) throw err;
console.log('XXX') // 把 MongoDB 查询代码放在这里
collection.insert(// 将一个文档插入到集合中,并输出其独有的文档ID
{
"title": "I like cake",
"body": "It is quite good."
},
{safe: true},// 安全模式表明数据库操作应该在回调执行之前完成
function(err, documents) {
if (err) throw err;
console.log('Document ID is: ' + documents[0]._id);
}
);
});
});
安全模式:在查询语句中声明{safe: true}表明你想让数据库操作在执行回调之前完成。如果你的回调逻辑对即将完成的数据库操作有任何形式的依赖,这就是你需要的选项。如果你的回调逻辑不依赖于数据库操作,可以用{}取代{safe: true}关闭安全模式
尽管你能用console.log将documents[0]._id显示为字符串,但实际上它不是字符串。MongoDB的文档标识符是二进制JSON(BSON)。BSON是MongoDB用来交换数据的主要数据格式,MongoDB服务器用它代替JSON交换数据。大多数情况下,它更节省空间,解析起来也更快。占用更少空间,扫描更容易意味着数据库交互更快。
(4) 更新MongoDB文档
var _id = new client.bson_serializer .ObjectID('4e650d344ac74b5a01000001');
collection.update(
{_id: _id},
{$set: {"title": "I ate too much cake"}},
{safe: true},
function(err) {
if (err) throw err;
}
);
3、Mongoose Mongoose的模型(模型视图控制器中的说法)提供了一个到MongoDB集合接口
- 使用步骤
(1)安装Mongoose
npm install mongoose
(2)启动MongoDB服务器
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/tasks');
(3)注册schema
var Schema = mongoose.Schema;
var Tasks = new Schema({
project: String,
description: String
});
mongoose.model('Task', Tasks);
(4)添加任务
var Task = mongoose.model('Task');
var task = new Task();
task.project = 'Bikeshed';
task.description = 'Paint the bikeshed red.';
task.save(function(err) {
if (err) throw err;
console.log('Task saved.');
});
(5) 搜索文档
var Task = mongoose.model('Task');
Task.find({'project': 'Bikeshed'}, function(err, tasks) {
for (var i = 0; i < tasks.length; i++) {
console.log('ID:' + tasks[i]._id);
console.log(tasks[i].description);
}
});