思考
当你注册QQ的时候,系统会给你生成一个唯一的数字账号。那么这个账号在后台是怎么生成的呢?当让实现方法有很多,可以直接生成一个随机数,然后查找该随机数有没有被注册过,若是没有,则生成成功,否则,重新执行以上步骤。这个方法有个很大的问题:随着注册的号码越来越多,以后每生成一个号码,可能要多次查询是否已经注册,效率太低!
我也查了一些资料,最简单的算法莫过于预先生成一批数字,作为一个号码池,以后注册时可以每次从号码池中取一个。当号码池中的号码不够用时可再生成一批。这样其实每次仅需查询一次数据库,看似最笨,实则效率极高,效果也较好。
实现
我们先生成10001到10099这99和账号,插入到数据库中,并在每个号码后面加上一个标志位,这样以后靓号可以标识为locked,保证不能被注册到。代码如下。
var mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1:27017/users');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("数据库连接成功");
let accountSchema = mongoose.Schema({
account: Number,
status: String
});
let accountModel = mongoose.model('account_pool', accountSchema);
for (var i = 10001; i <= 10099; i++) {
let account = new accountModel({
account: i,
status: "ok"
});
account.save(function (error, newAccount) {
if (error) {
console.log("插入 " + account + " 错误:" + error);
} else {
console.log("已成功插入 " + newAccount);
}
});
}
});
我们并非批量插入,而是一个个循环插入,其实数据插入的顺序并不是固定的,你看下log就知道了。这样也算是稍微的一点点随机,使得连续注册不会注册到连续的号码。启动数据库之后,将上面的代码保存到文件accountGen.js中运行如下命令即可生成好号码池。
node accountGen.js
同样,每次注册时候去号码池中取一个。
function createAccountNumber(callback) {
accountModel.findOneAndRemove({status: "ok"}, function (err, newAccount) {
if (err) {
console.log("createAccountNumber err:" + err);
callback(err, null)
} else if (!newAccount) {
console.log("createAccountNumber newAccount null");
callback(null, null)
} else {
console.log("createAccountNumber result:" + newAccount);
callback(null, newAccount.account)
}
})
}
大功告成!非常简单。
接下来要做的事情
目前看来系统已经可以运行了,但是却缺少了一个重要的东西:日志系统。服务器没有日志是不行的,下面我将学习如何使用log4js。