热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Sequelize和MySQL对比

假如你以为Sequelize的文档有点多、杂,不轻易看,可以看看这篇。在运用NodeJS来关联型操纵数据库时,为了轻易,平常都邑挑选一个适宜的ORM(ObjectRelations

假如你以为Sequelize的文档有点多、杂,不轻易看,可以看看这篇。

在运用NodeJS来关联型操纵数据库时,为了轻易,平常都邑挑选一个适宜的ORM(Object Relationship Model)框架。毕竟直接操纵SQL比较烦琐,经由过程ORM框架,我们可以运用面向对象的体式格局来操纵表。NodeJS社区有很多的ORM框架,我比较喜好Sequelize,它功用雄厚,可以非常轻易的举行连表查询。

这篇文章我们就来看看,Sequelize是如安在SQL之上举行笼统、封装,从而进步开辟效力的。

装置

这篇文章重要运用MySQLSequelizeco来举行引见。装置非常简朴:

$ npm install --save co
$ npm install --save sequelize
$ npm install --save mysql

代码模板以下:

var Sequelize = require('sequelize');
var co = require('co');
co(function* () {
// code here
}).catch(function(e) {
console.log(e);
});

基础上,Sequelize的操纵都邑返回一个Promise,在co的框架内里可以直接举行yield,非常轻易。

竖立数据库衔接

var sequelize = new Sequelize(
'sample', // 数据库名
'root', // 用户名
'zuki', // 用户暗码
{
'dialect': 'mysql', // 数据库运用mysql
'host': 'localhost', // 数据库服务器ip
'port': 3306, // 数据库服务器端口
'define': {
// 字段以下划线(_)来支解(默许是驼峰定名作风)
'underscored': true
}
}
);
定义单张表

Sequelize

var User = sequelize.define(
// 默许表名(平常这里写单数),天生时会自动转换成复数情势
// 这个值还会作为接见模子相干的模子时的属性名,所以发起用小写情势
'user',
// 字段定义(主键、created_at、updated_at默许包括,不必特别定义)
{
'emp_id': {
'type': Sequelize.CHAR(10), // 字段范例
'allowNull': false, // 是不是许可为NULL
'unique': true // 字段是不是UNIQUE
},
'nick': {
'type': Sequelize.CHAR(10),
'allowNull': false
},
'department': {
'type': Sequelize.STRING(64),
'allowNull': true
}
}
);

SQL

CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER NOT NULL auto_increment ,
`emp_id` CHAR(10) NOT NULL UNIQUE,
`nick` CHAR(10) NOT NULL,
`department` VARCHAR(64),
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;

几点申明:

  1. 建表SQL会自动实行的意义是你主动挪用sync的时刻。相似如许:User.sync({force: true});(加force:true,会先删掉表后再建表)。我们也可以先定义好表构造,再来定义Sequelize模子,这时候可以不必sync。二者在定义阶段没有什么关联,直到我们真正最先操纵模子时,才会触及到表的操纵,然则我们固然照样要只管保证模子和表的同步(可以借助一些migration东西)。自动建表功用有风险,运用需谨慎。

  2. 一切数据范例,请参考文档数据范例。

  3. 模子还可以定义假造属性、类要领、实例要领,请参考文档:模子定义

  4. 其他一些特别定义以下所示:

var User = sequelize.define(
'user',
{
'emp_id': {
'type': Sequelize.CHAR(10), // 字段范例
'allowNull': false, // 是不是许可为NULL
'unique': true // 字段是不是UNIQUE
},
'nick': {
'type': Sequelize.CHAR(10),
'allowNull': false
},
'department': {
'type': Sequelize.STRING(64),
'allowNull': true
}
},
{
// 自定义表名
'freezeTableName': true,
'tableName': 'xyz_users',
// 是不是需要增添createdAt、updatedAt、deletedAt字段
'timestamps': true,
// 不需要createdAt字段
'createdAt': false,
// 将updatedAt字段改个名
'updatedAt': 'utime'
// 将deletedAt字段更名
// 同时需要设置paranoid为true(此种形式下,删除数据时不会举行物理删除,而是设置deletedAt为当前时候
'deletedAt': 'dtime',
'paranoid': true
}
);
单表增编削查

经由过程Sequelize猎取的模子对象都是一个DAO(Data Access Object)对象,这些对象会具有很多操纵数据库表的实例对象要领(比方:saveupdatedestroy等),需要猎取“清洁”的JSON对象可以挪用get({'plain': true})

经由过程模子的类要领可以猎取模子对象(比方:findByIdfindAll等)。

Sequelize

// 要领1:build后对象只存在于内存中,挪用save后才操纵db
var user = User.build({
'emp_id': '1',
'nick': '小红',
'department': '技术部'
});
user = yield user.save();
console.log(user.get({'plain': true}));
// 要领2:直接操纵db
var user = yield User.create({
'emp_id': '2',
'nick': '小明',
'department': '技术部'
});
console.log(user.get({'plain': true}));

SQL

INSERT INTO `users`
(`id`, `emp_id`, `nick`, `department`, `updated_at`, `created_at`)
VALUES
(DEFAULT, '1', '小红', '技术部', '2015-11-02 14:49:54', '2015-11-02 14:49:54');

Sequelize会为主键id设置DEFAULT值来让数据库发作自增值,还将当前时候设置成了created_atupdated_at字段,非常轻易。

Sequelize

// 要领1:操纵对象属性(不会操纵db),挪用save后操纵db
user.nick = '小白';
user = yield user.save();
console.log(user.get({'plain': true}));
// 要领2:直接update操纵db
user = yield user.update({
'nick': '小白白'
});
console.log(user.get({'plain': true}));

SQL

UPDATE `users`
SET `nick` = '小白白', `updated_at` = '2015-11-02 15:00:04'
WHERE `id` = 1;

更新操纵时,Sequelize将将当前时候设置成了updated_at,非常轻易。

假如想限定更新属性的白名单,可以如许写:

// 要领1
user.emp_id = '33';
user.nick = '小白';
user = yield user.save({'fields': ['nick']});
// 要领2
user = yield user.update(
{'emp_id': '33', 'nick': '小白'},
{'fields': ['nick']}
});

如许就只会更新nick字段,而emp_id会被疏忽。这类要领在对表单提交过来的一大推数据中只更新某些属性的时刻比较有效。

Sequelize

yield user.destroy();

SQL

DELETE FROM `users` WHERE `id` = 1;

这里有个特别的处所是,假如我们开启了paranoid(偏执)形式,destroy的时刻不会实行DELETE语句,而是实行一个UPDATE语句将deleted_at字段设置为当前时候(一最先此字段值为NULL)。我们可以运用user.destroy({force: true})来强迫删除,从而实行DELETE语句举行物理删除。

查悉数

Sequelize

var users = yield User.findAll();
console.log(users);

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at` FROM `users`;

限定字段

Sequelize

var users = yield User.findAll({
'attributes': ['emp_id', 'nick']
});
console.log(users);

SQL

SELECT `emp_id`, `nick` FROM `users`;

字段重定名

Sequelize

var users = yield User.findAll({
'attributes': [
'emp_id', ['nick', 'user_nick']
]
});
console.log(users);

SQL

SELECT `emp_id`, `nick` AS `user_nick` FROM `users`;

where子句

Sequelizewhere设置项基础上完整支撑了SQLwhere子句的功用,非常壮大。我们一步步来举行引见。

基础前提

Sequelize

var users = yield User.findAll({
'where': {
'id': [1, 2, 3],
'nick': 'a',
'department': null
}
});
console.log(users);

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
`user`.`id` IN (1, 2, 3) AND
`user`.`nick`='a' AND
`user`.`department` IS NULL;

可以看到,k: v被转换成了k = v,同时一个对象的多个k: v对被转换成了AND前提,即:k1: v1, k2: v2转换为k1 = v1 AND k2 = v2

这里有2个要点:

  • 假如v是null,会转换为IS NULL(由于SQL没有= NULL
    这类语法)

  • 假如v是数组,会转换为IN前提(由于SQL没有=[1,2,3]这类语法,何况也没数组这类范例)

操纵符

操纵符是对某个字段的进一步束缚,可以有多个(对同一个字段的多个操纵符会被转化为AND)。

Sequelize

var users = yield User.findAll({
'where': {
'id': {
'$eq': 1, // id = 1
'$ne': 2, // id != 2
'$gt': 6, // id > 6
'$gte': 6, // id >= 6
'$lt': 10, // id <10
'$lte': 10, // id <= 10
'$between': [6, 10], // id BETWEEN 6 AND 10
'$notBetween': [11, 15], // id NOT BETWEEN 11 AND 15
'$in': [1, 2], // id IN (1, 2)
'$notIn': [3, 4] // id NOT IN (3, 4)
},
'nick': {
'$like': '%a%', // nick LIKE '%a%'
'$notLike': '%a' // nick NOT LIKE '%a'
},
'updated_at': {
'$eq': null, // updated_at IS NULL
'$ne': null // created_at IS NOT NULL
}
}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` = 1 AND
`user`.`id` != 2 AND
`user`.`id` > 6 AND
`user`.`id` >= 6 AND
`user`.`id` <10 AND
`user`.`id` <= 10 AND
`user`.`id` BETWEEN 6 AND 10 AND
`user`.`id` NOT BETWEEN 11 AND 15 AND
`user`.`id` IN (1, 2) AND
`user`.`id` NOT IN (3, 4)
)
AND
(
`user`.`nick` LIKE '%a%' AND
`user`.`nick` NOT LIKE '%a'
)
AND
(
`user`.`updated_at` IS NULL AND
`user`.`updated_at` IS NOT NULL
);

这里我们发明,实在相称前提k: v这类写法是操纵符写法k: {$eq: v}的简写。而要完成不等前提就必须运用操纵符写法k: {$ne: v}

前提

上面我们说的前提查询,都是AND查询,Sequelize同时也支撑ORNOT、以至多种前提的团结查询。

AND前提

Sequelize

var users = yield User.findAll({
'where': {
'$and': [
{'id': [1, 2]},
{'nick': null}
]
}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` IN (1, 2) AND
`user`.`nick` IS NULL
);

OR前提

Sequelize

var users = yield User.findAll({
'where': {
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` IN (1, 2) OR
`user`.`nick` IS NULL
);

NOT前提

Sequelize

var users = yield User.findAll({
'where': {
'$not': [
{'id': [1, 2]},
{'nick': null}
]
}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
NOT (
`user`.`id` IN (1, 2) AND
`user`.`nick` IS NULL
);

转换规则

我们这里做个总结。Sequelizewhere设置的转换规则的伪代码也许以下:

function translate(where) {
for (k, v of where) {
if (k == 表字段) {
// 先一致转为操纵符情势
if (v == 基础值) { // k: 'xxx'
v = {'$eq': v};
}
if (v == 数组) { // k: [1, 2, 3]
v = {'$in': v};
}
// 操纵符转换
for (opk, opv of v) {
// op将opk转换对应的SQL示意
=> k + op(opk, opv) + AND;
}
}
// 逻辑操纵符处置惩罚
if (k == '$and') {
for (item in v) {
=> translate(item) + AND;
}
}
if (k == '$or') {
for (item in v) {
=> translate(item) + OR;
}
}
if (k == '$not') {
NOT +
for (item in v) {
=> translate(item) + AND;
}
}
}
function op(opk, opv) {
switch (opk) {
case $eq => ('=' + opv) || 'IS NULL';
case $ne => ('!=' + opv) || 'IS NOT NULL';
case $gt => '>' + opv;
case $lt => '<' + opv;
case $gte => '>=' + opv;
case $lte => '<=' + opv;
case $between => 'BETWEEN ' + opv[0] + ' AND ' + opv[1];
case $notBetween => 'NOT BETWEEN ' + opv[0] + ' AND ' + opv[1];
case $in => 'IN (' + opv.join(',') + ')';
case $notIn => 'NOT IN (' + opv.join(',') + ')';
case $like => 'LIKE ' + opv;
case $notLike => 'NOT LIKE ' + opv;
}
}
}

我们看一个庞杂例子,基础上就是按上述流程来举行转换。

Sequelize

var users = yield User.findAll({
'where': {
'id': [3, 4],
'$not': [
{
'id': {
'$in': [1, 2]
}
},
{
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
],
'$and': [
{'id': [1, 2]},
{'nick': null}
],
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
`user`.`id` IN (3, 4)
AND
NOT
(
`user`.`id` IN (1, 2)
AND
(`user`.`id` IN (1, 2) OR `user`.`nick` IS NULL)
)
AND
(
`user`.`id` IN (1, 2) AND `user`.`nick` IS NULL
)
AND
(
`user`.`id` IN (1, 2) OR `user`.`nick` IS NULL
);

排序

Sequelize

var users = yield User.findAll({
'order': [
['id', 'DESC'],
['nick']
]
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
ORDER BY `user`.`id` DESC, `user`.`nick`;

分页

Sequelize

var countPerPage = 20, currentPage = 5;
var users = yield User.findAll({
'limit': countPerPage, // 每页若干条
'offset': countPerPage * (currentPage - 1) // 跳过若干条
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
LIMIT 80, 20;

其他查询要领

查询一条数据

Sequelize

user = yield User.findById(1);
user = yield User.findOne({
'where': {'nick': 'a'}
});

SQL

SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE `user`.`id` = 1 LIMIT 1;
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE `user`.`nick` = 'a' LIMIT 1;

查询并猎取数目

Sequelize

var result = yield User.findAndCountAll({
'limit': 20,
'offset': 0
});
console.log(result);

SQL

SELECT count(*) AS `count` FROM `users` AS `user`;
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
LIMIT 20;

这个要领会实行2个SQL,返回的result对象将包括2个字段:result.count是数据总数,result.rows是相符查询前提的一切数据。

批量操纵

插进去

Sequelize

var users = yield User.bulkCreate(
[
{'emp_id': 'a', 'nick': 'a'},
{'emp_id': 'b', 'nick': 'b'},
{'emp_id': 'c', 'nick': 'c'}
]
);

SQL

INSERT INTO `users`
(`id`,`emp_id`,`nick`,`created_at`,`updated_at`)
VALUES
(NULL,'a','a','2015-11-03 02:43:30','2015-11-03 02:43:30'),
(NULL,'b','b','2015-11-03 02:43:30','2015-11-03 02:43:30'),
(NULL,'c','c','2015-11-03 02:43:30','2015-11-03 02:43:30');

这里需要注重,返回的users数组内里每一个对象的id值会是null。假如需要id值,可以从新取下数据。

更新

Sequelize

var affectedRows = yield User.update(
{'nick': 'hhhh'},
{
'where': {
'id': [2, 3, 4]
}
}
);

SQL

UPDATE `users`
SET `nick`='hhhh',`updated_at`='2015-11-03 02:51:05'
WHERE `id` IN (2, 3, 4);

这里返回的affectedRows现实上是一个数组,内里只要一个元素,示意更新的数据条数(看起来像是Sequelize的一个bug)。

删除

Sequelize

var affectedRows = yield User.destroy({
'where': {'id': [2, 3, 4]}
});

SQL

DELETE FROM `users` WHERE `id` IN (2, 3, 4);

这里返回的affectedRows是一个数字,示意删除的数据条数。

关联

关联平常有三种:一对一、一对多、多对多。Sequelize供应了清楚易用的接口来定义关联、举行表间的操纵。

当说到关联查询时,平常会需要猎取多张表的数据。有发起用连表查询join的,有不发起的。我的意见是,join查询这类黑科技在数据量小的状况下可以运用,基础没有什么影响,数据量大的时刻,join的机能可以会是硬伤,应当只管防止,可以离别依据索引取单表数据然后在应用层对数据举行joinmerge。固然,查询时一定要分页,不要findAll

一对一

模子定义

Sequelize

var User = sequelize.define('user',
{
'emp_id': {
'type': Sequelize.CHAR(10),
'allowNull': false,
'unique': true
}
}
);
var Account = sequelize.define('account',
{
'email': {
'type': Sequelize.CHAR(20),
'allowNull': false
}
}
);
/*
* User的实例对象将具有getAccount、setAccount、addAccount要领
*/
User.hasOne(Account);
/*
* Account的实例对象将具有getUser、setUser、addUser要领
*/
Account.belongsTo(User);

SQL

CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER NOT NULL auto_increment ,
`emp_id` CHAR(10) NOT NULL UNIQUE,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` INTEGER NOT NULL auto_increment ,
`email` CHAR(20) NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`user_id` INTEGER,
PRIMARY KEY (`id`),
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB;

可以看到,这类关联中外键user_id加在了Account上。别的,Sequelize还给我们天生了外键束缚。

平常来说,外键束缚在有些自身定制的数据库系统内里是制止的,由于会带来一些机能题目。所以,建表的SQL平常就去掉束缚,同时给外键加一个索引(加快查询),数据的一致性就靠应用层来保证了。

关联操纵

Sequelize

var user = yield User.create({'emp_id': '1'});
var account = user.createAccount({'email': 'a'});
console.log(account.get({'plain': true}));

SQL

INSERT INTO `users`
(`id`,`emp_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'1','2015-11-03 06:24:53','2015-11-03 06:24:53');
INSERT INTO `accounts`
(`id`,`email`,`user_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'a',1,'2015-11-03 06:24:53','2015-11-03 06:24:53');

SQL实行逻辑是:

  • 运用对应的的user_id作为外键在accounts内外插进去一条数据。

Sequelize

var anotherAccount = yield Account.create({'email': 'b'});
console.log(anotherAccount);
anotherAccount = yield user.setAccount(anotherAccount);
console.log(anotherAccount);

SQL

INSERT INTO `accounts`
(`id`,`email`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'b','2015-11-03 06:37:14','2015-11-03 06:37:14');
SELECT `id`, `email`, `created_at`, `updated_at`, `user_id`
FROM `accounts` AS `account` WHERE (`account`.`user_id` = 1);
UPDATE `accounts` SET `user_id`=NULL,`updated_at`='2015-11-03 06:37:14' WHERE `id` = 1;
UPDATE `accounts` SET `user_id`=1,`updated_at`='2015-11-03 06:37:14' WHERE `id` = 2;

SQL实行逻辑是:

  • 插进去一条account数据,此时外键user_id是空的,还没有关联user

  • 找出当前user所关联的account并将其user_id置为`NUL(为了保证一对一关联)

  • 设置新的acount的外键user_iduser的属性id,天生关联

Sequelize

yield user.setAccount(null);

SQL

SELECT `id`, `email`, `created_at`, `updated_at`, `user_id`
FROM `accounts` AS `account`
WHERE (`account`.`user_id` = 1);
UPDATE `accounts`
SET `user_id`=NULL,`updated_at`='2015-11-04 00:11:35'
WHERE `id` = 1;

这里的删除现实上只是“割断”关联,并不会真正的物理删除纪录。

SQL实行逻辑是:

  • 找出user所关联的account数据

  • 将其外键user_id设置为NULL,完成关联的“割断”

Sequelize

var account = yield user.getAccount();
console.log(account);

SQL

SELECT `id`, `email`, `created_at`, `updated_at`, `user_id`
FROM `accounts` AS `account`
WHERE (`account`.`user_id` = 1);

这里就是挪用usergetAccount要领,依据外键来猎取对应的account

然则实在我们用面向对象的头脑来思索应当是猎取user的时刻就可以经由过程user.account的体式格局来接见account对象。这可以经由过程Sequelizeeager loading(急加载,和懒加载相反)来完成。

eager loading的寄义是说,取一个模子的时刻,同时也把相干的模子数据也给我取过来(我很着急,不能按默许那种取一个模子就取一个模子的体式格局,我还要更多)。要领以下:

Sequelize

var user = yield User.findById(1, {
'include': [Account]
});
console.log(user.get({'plain': true}));
/*
* 输出相似:
{ id: 1,
emp_id: '1',
created_at: Tue Nov 03 2015 15:25:27 GMT+0800 (CST),
updated_at: Tue Nov 03 2015 15:25:27 GMT+0800 (CST),
account:
{ id: 2,
email: 'b',
created_at: Tue Nov 03 2015 15:25:27 GMT+0800 (CST),
updated_at: Tue Nov 03 2015 15:25:27 GMT+0800 (CST),
user_id: 1 } }
*/

SQL

SELECT `user`.`id`, `user`.`emp_id`, `user`.`created_at`, `user`.`updated_at`, `account`.`id` AS `account.id`, `account`.`email` AS `account.email`, `account`.`created_at` AS `account.created_at`, `account`.`updated_at` AS `account.updated_at`, `account`.`user_id` AS `account.user_id`
FROM `users` AS `user` LEFT OUTER JOIN `accounts` AS `account`
ON `user`.`id` = `account`.`user_id`
WHERE `user`.`id` = 1 LIMIT 1;

可以看到,我们对2个表举行了一个外连接,从而在取user的同时也猎取到了account

其他补充申明

假如我们反复挪用user.createAccount要领,现实上会在数据库内里天生多条user_id一样的数据,并非真正的一对一。

所以,在应用层保证一致性时,就需要我们遵照优越的编码商定。新增就用user.createAccount,变动就用user.setAccount

也可以给user_id加一个UNIQUE束缚,在数据库层面保证一致性,这时候就需要做好try/catch,发作插进去非常的时刻可以晓得是由于插进去了多个account

别的,我们上面都是运用user来对account举行操纵。现实上反向操纵也是可以的,这是由于我们定义了Account.belongsTo(User)。在Sequelize内里定义关联时,关联的挪用方会取得相干的“关联”要领,平常为了双方都能操纵,会同时定义双向关联(这里双向关联指的是模子层面,并不会在数据库表中涌现两个表都加上外键的状况,请宁神)。

一对多

模子定义

Sequelize

var User = sequelize.define('user',
{
'emp_id': {
'type': Sequelize.CHAR(10),
'allowNull': false,
'unique': true
}
}
);
var Note = sequelize.define('note',
{
'title': {
'type': Sequelize.CHAR(64),
'allowNull': false
}
}
);
/*
* User的实例对象将具有getNotes、setNotes、addNote、createNote、removeNote、hasNote要领
*/
User.hasMany(Note);
/*
* Note的实例对象将具有getUser、setUser、createUser要领
*/
Note.belongsTo(User);

SQL

CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER NOT NULL auto_increment ,
`emp_id` CHAR(10) NOT NULL UNIQUE,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `notes` (
`id` INTEGER NOT NULL auto_increment ,
`title` CHAR(64) NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`user_id` INTEGER,
PRIMARY KEY (`id`),
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB;

可以看到这类关联中,外键user_id加在了多的一端(notes表)。同时相干的模子也自动取得了一些要领。

关联操纵

要领1

Sequelize

var user = yield User.create({'emp_id': '1'});
var note = yield user.createNote({'title': 'a'});
console.log(note);

SQL

NSERT INTO `users`
(`id`,`emp_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'1','2015-11-03 23:52:05','2015-11-03 23:52:05');
INSERT INTO `notes`
(`id`,`title`,`user_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'a',1,'2015-11-03 23:52:05','2015-11-03 23:52:05');

SQL实行逻辑:

  • 运用user的主键id值作为外键直接在notes内外插进去一条数据。

要领2

Sequelize

var user = yield User.create({'emp_id': '1'});
var note = yield Note.create({'title': 'b'});
yield user.addNote(note);

SQL

INSERT INTO `users`
(`id`,`emp_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'1','2015-11-04 00:02:56','2015-11-04 00:02:56');
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'b','2015-11-04 00:02:56','2015-11-04 00:02:56');
UPDATE `notes`
SET `user_id`=1,`updated_at`='2015-11-04 00:02:56'
WHERE `id` IN (1);

SQL实行逻辑:

  • 插进去一条note数据,此时该条数据的外键user_id为空

  • 运用user的属性id值再更新该条note数据,设置好外键,完成关联竖立

Sequelize

// 为user增添note1、note2
var user = yield User.create({'emp_id': '1'});
var note1 = yield user.createNote({'title': 'a'});
var note2 = yield user.createNote({'title': 'b'});
// 先建立note3、note4
var note3 = yield Note.create({'title': 'c'});
var note4 = yield Note.create({'title': 'd'});
// user具有的note变动为note3、note4
yield user.setNotes([note3, note4]);

SQL

/* 省去了建立语句 */
SELECT `id`, `title`, `created_at`, `updated_at`, `user_id`
FROM `notes` AS `note` WHERE `note`.`user_id` = 1;
UPDATE `notes`
SET `user_id`=NULL,`updated_at`='2015-11-04 12:45:12'
WHERE `id` IN (1, 2);
UPDATE `notes`
SET `user_id`=1,`updated_at`='2015-11-04 12:45:12'
WHERE `id` IN (3, 4);

SQL实行逻辑:

  • 依据user的属性id查询一切相干的note数据

  • note1note2的外键user_id置为NULL,割断关联

  • note3note4的外键user_id置为user的属性id,完成关联竖立

这里为啥还要查出一切的note数据呢?由于我们需要依据传人setNotes的数组来盘算出哪些note要割断关联、哪些要新增关联,所以就需要查出来举行一个盘算鸠合的“交集”运算。

Sequelize

var user = yield User.create({'emp_id': '1'});
var note1 = yield user.createNote({'title': 'a'});
var note2 = yield user.createNote({'title': 'b'});
yield user.setNotes([]);

SQL

SELECT `id`, `title`, `created_at`, `updated_at`, `user_id`
FROM `notes` AS `note` WHERE `note`.`user_id` = 1;
UPDATE `notes`
SET `user_id`=NULL,`updated_at`='2015-11-04 12:50:08'
WHERE `id` IN (1, 2);

现实上,上面说到的“改”已有“删”的操纵了(去掉note1note2的关联)。这里的操纵是删掉用户的一切note数据,直接实行user.setNotes([])即可。

SQL实行逻辑:

  • 依据user的属性id查出一切相干的note数据

  • 将其外键user_id置为NULL,割断关联

另有一个真正的删除要领,就是removeNote。以下所示:

Sequelize

yield user.removeNote(note);

SQL

UPDATE `notes`
SET `user_id`=NULL,`updated_at`='2015-11-06 01:40:12'
WHERE `user_id` = 1 AND `id` IN (1);

状况1

查询user的一切满足前提的note数据。

Sequelize

var notes = yield user.getNotes({
'where': {
'title': {
'$like': '%css%'
}
}
});
notes.forEach(function(note) {
console.log(note);
});

SQL

SELECT `id`, `title`, `created_at`, `updated_at`, `user_id`
FROM `notes` AS `note`
WHERE (`note`.`user_id` = 1 AND `note`.`title` LIKE '%a%');

这类要领的SQL很简朴,直接依据userid值来查询满足前提的note即可。

状况2

查询一切满足前提的note,同时猎取note属于哪一个user

Sequelize

var notes = yield Note.findAll({
'include': [User],
'where': {
'title': {
'$like': '%css%'
}
}
});
notes.forEach(function(note) {
// note属于哪一个user可以经由过程note.user接见
console.log(note);
});

SQL

SELECT `note`.`id`, `note`.`title`, `note`.`created_at`, `note`.`updated_at`, `note`.`user_id`,
`user`.`id` AS `user.id`, `user`.`emp_id` AS `user.emp_id`, `user`.`created_at` AS `user.created_at`, `user`.`updated_at` AS `user.updated_at`
FROM `notes` AS `note` LEFT OUTER JOIN `users` AS `user`
ON `note`.`user_id` = `user`.`id`
WHERE `note`.`title` LIKE '%css%';

这类要领,由于猎取的主体是note,所以将notesleft joinusers

状况3

查询一切满足前提的user,同时猎取该user一切满足前提的note

Sequelize

var users = yield User.findAll({
'include': [Note],
'where': {
'created_at': {
'$lt': new Date()
}
}
});
users.forEach(function(user) {
// user的notes可以经由过程user.notes接见
console.log(user);
});

SQL

SELECT `user`.`id`, `user`.`emp_id`, `user`.`created_at`, `user`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`, `notes`.`user_id` AS `notes.user_id`
FROM `users` AS `user` LEFT OUTER JOIN `notes` AS `notes`
ON `user`.`id` = `notes`.`user_id`
WHERE `user`.`created_at` <'2015-11-05 01:51:35';

这类要领猎取的主体是user,所以将usersleft joinnotes

一点补充

关于种种join的区分,可以参考:http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/。

关于eager loading我想再烦琐几句。include内里通报的是去取相干模子,默许是取悉数,我们也可以再对这个模子举行一层过滤。像下面如许:

Sequelize

// 查询建立时候在本日之前的一切user,同时猎取他们note的题目中含有关键字css的一切note
var users = yield User.findAll({
'include': [
{
'model': Note,
'where': {
'title': {
'$like': '%css%'
}
}
}
],
'where': {
'created_at': {
'$lt': new Date()
}
}
});

SQL

SELECT `user`.`id`, `user`.`emp_id`, `user`.`created_at`, `user`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`, `notes`.`user_id` AS `notes.user_id`
FROM `users` AS `user` INNER JOIN `notes` AS `notes`
ON `user`.`id` = `notes`.`user_id` AND `notes`.`title` LIKE '%css%'
WHERE `user`.`created_at` <'2015-11-05 01:58:31';

注重:当我们对include的模子加了where过滤时,会运用inner join来举行查询,如许保证只要那些具有题目含有css关键词note的用户才会返回。

多对多关联

在多对多关联中,必需要分外一张关联表来将2个表举行关联,这张表可所以纯真的一个关联表,也可所以一个现实的模子(含有自身的分外属性来形貌关联)。我比较喜好用一个模子的体式格局,如许轻易今后做扩大。

模子定义

Sequelize

var Note = sequelize.define('note',
{
'title': {
'type': Sequelize.CHAR(64),
'allowNull': false
}
}
);
var Tag = sequelize.define('tag',
{
'name': {
'type': Sequelize.CHAR(64),
'allowNull': false,
'unique': true
}
}
);
var Tagging = sequelize.define('tagging',
{
'type': {
'type': Sequelize.INTEGER(),
'allowNull': false
}
}
);
// Note的实例具有getTags、setTags、addTag、addTags、createTag、removeTag、hasTag要领
Note.belongsToMany(Tag, {'through': Tagging});
// Tag的实例具有getNotes、setNotes、addNote、addNotes、createNote、removeNote、hasNote要领
Tag.belongsToMany(Note, {'through': Tagging});

SQL

CREATE TABLE IF NOT EXISTS `notes` (
`id` INTEGER NOT NULL auto_increment ,
`title` CHAR(64) NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `tags` (
`id` INTEGER NOT NULL auto_increment ,
`name` CHAR(64) NOT NULL UNIQUE,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `taggings` (
`type` INTEGER NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`tag_id` INTEGER ,
`note_id` INTEGER ,
PRIMARY KEY (`tag_id`, `note_id`),
FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`note_id`) REFERENCES `notes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

可以看到,多对多关联中零丁天生了一张关联表,并设置了2个外键tag_idnote_id来和tagsnotes举行关联。关于关联表的定名,我比较喜好运用动词,由于这张表是用来示意两张表的一种联络,而且这类联络多半时刻伴随着一种行动。比方:用户珍藏商品(collecting)、用户购置商品(buying)、用户到场项目(joining)等等。

要领1

Sequelize

var note = yield Note.create({'title': 'note'});
yield note.createTag({'name': 'tag'}, {'type': 0});

SQL

INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:14:38','2015-11-06 02:14:38');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag','2015-11-06 02:14:38','2015-11-06 02:14:38');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,0,'2015-11-06 02:14:38','2015-11-06 02:14:38');

SQL实行逻辑:

  • notes表插进去纪录

  • tags表中插进去纪录

  • 运用对应的值设置外键tag_idnote_id以及关联模子自身需要的属性(type: 0)在关联表tagging中插进去纪录

关联表自身需要的属性,经由过程通报一个分外的对象给设置要领来完成。

要领2

Sequelize

var note = yield Note.create({'title': 'note'});
var tag = yield Tag.create({'name': 'tag'});
yield note.addTag(tag, {'type': 1});

SQL

INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:20:52','2015-11-06 02:20:52');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag','2015-11-06 02:20:52','2015-11-06 02:20:52');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,1,'2015-11-06 02:20:52','2015-11-06 02:20:52');

这类要领和上面的要领现实上是一样的。只是我们先手动create了一个Tag模子。

要领3

Sequelize

var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2], {'type': 2});

SQL

INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag1','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag2','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `taggings` (`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18'),
(2,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18');

这类要领可以举行批量增加。当实行addTags时,现实上就是设置好对应的外键及关联模子自身的属性,然后在关联表中批量的插进去数据。

Sequelize

// 先增加几个tag
var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2], {'type': 2});
// 将tag改掉
var tag3 = yield Tag.create({'name': 'tag3'});
var tag4 = yield Tag.create({'name': 'tag4'});
yield note.setTags([tag3, tag4], {'type': 3});

SQL

/* 前面增加部份的sql,和上面一样*/
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag1','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag2','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18'),
(2,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18');
/* 变动部份的sql */
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag3','2015-11-06 02:29:55','2015-11-06 02:29:55');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag4','2015-11-06 02:29:55','2015-11-06 02:29:55');
/* 先删除关联 */
DELETE FROM `taggings`
WHERE `note_id` = 1 AND `tag_id` IN (1, 2);
/* 插进去新关联 */
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(3,1,3,'2015-11-06 02:29:55','2015-11-06 02:29:55'),
(4,1,3,'2015-11-06 02:29:55','2015-11-06 02:29:55');

实行逻辑是,先将tag1tag2在关联表中的关联删除,然后再将tag3tag4对应的关联插进去关联表。

Sequelize

// 先增加几个tag
var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
var tag3 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2, tag3], {'type': 2});
// 删除一个
yield note.removeTag(tag1);
// 悉数删除
yield note.setTags([]);

SQL

/* 删除一个 */
DELETE FROM `taggings` WHERE `note_id` = 1 AND `tag_id` IN (1);
/* 删除悉数 */
SELECT `type`, `created_at`, `updated_at`, `tag_id`, `note_id`
FROM `taggings` AS `tagging`
WHERE `tagging`.`note_id` = 1;
DELETE FROM `taggings` WHERE `note_id` = 1 AND `tag_id` IN (2, 3);

删除一个很简朴,直接将关联表中的数据删除。

悉数删除时,起首需要查出关联表中note_id对应的一切数据,然后一次删掉。

状况1

查询note一切满足前提的tag

Sequelize

var tags = yield note.getTags({
//这里可以对tags举行where
});
tags.forEach(function(tag) {
// 关联模子可以经由过程tag.tagging来接见
console.log(tag);
});

SQL

SELECT `tag`.`id`, `tag`.`name`, `tag`.`created_at`, `tag`.`updated_at`,
`tagging`.`type` AS `tagging.type`, `tagging`.`created_at` AS `tagging.created_at`, `tagging`.`updated_at` AS `tagging.updated_at`, `tagging`.`tag_id` AS `tagging.tag_id`, `tagging`.`note_id` AS `tagging.note_id`
FROM `tags` AS `tag`
INNER JOIN `taggings` AS `tagging`
ON
`tag`.`id` = `tagging`.`tag_id` AND `tagging`.`note_id` = 1;

可以看到这类查询,就是实行一个inner join

状况2

查询一切满足前提的tag,同时猎取每一个tag地点的note

Sequelize

var tags = yield Tag.findAll({
'include': [
{
'model': Note
// 这里可以对notes举行where
}
]
// 这里可以对tags举行where
});
tags.forEach(function(tag) {
// tag的notes可以经由过程tag.notes接见,关联模子可以经由过程tag.notes[0].tagging接见
console.log(tag);
});

SQL

SELECT `tag`.`id`, `tag`.`name`, `tag`.`created_at`, `tag`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`,
`notes.tagging`.`type` AS `notes.tagging.type`, `notes.tagging`.`created_at` AS `notes.tagging.created_at`, `notes.tagging`.`updated_at` AS `notes.tagging.updated_at`, `notes.tagging`.`tag_id` AS `notes.tagging.tag_id`, `notes.tagging`.`note_id` AS `notes.tagging.note_id`
FROM `tags` AS `tag`
LEFT OUTER JOIN
(
`taggings` AS `notes.tagging` INNER JOIN `notes` AS `notes`
ON
`notes`.`id` = `notes.tagging`.`note_id`
)
ON `tag`.`id` = `notes.tagging`.`tag_id`;

这个查询就轻微有点庞杂。起首是notestaggings举行了一个inner join,选出notes;然后tags和刚join出的鸠合再做一次left join,获得效果。

状况3

查询一切满足前提的note,同时猎取每一个note一切满足前提的tag

Sequelize

var notes = yield Note.findAll({
'include': [
{
'model': Tag
// 这里可以对tags举行where
}
]
// 这里可以对notes举行where
});
notes.forEach(function(note) {
// note的tags可以经由过程note.tags接见,关联模子经由过程note.tags[0].tagging接见
console.log(note);
});

SQL

SELECT
`note`.`id`, `note`.`title`, `note`.`created_at`, `note`.`updated_at`,
`tags`.`id` AS `tags.id`, `tags`.`name` AS `tags.name`, `tags`.`created_at` AS `tags.created_at`, `tags`.`updated_at` AS `tags.updated_at`,
`tags.tagging`.`type` AS `tags.tagging.type`, `tags.tagging`.`created_at` AS `tags.tagging.created_at`, `tags.tagging`.`updated_at` AS `tags.tagging.updated_at`, `tags.tagging`.`tag_id` AS `tags.tagging.tag_id`, `tags.tagging`.`note_id` AS `tags.tagging.note_id`
FROM `notes` AS `note`
LEFT OUTER JOIN
(
`taggings` AS `tags.tagging` INNER JOIN `tags` AS `tags`
ON
`tags`.`id` = `tags.tagging`.`tag_id`
)
ON
`note`.`id` = `tags.tagging`.`note_id`;

这个查询和上面的查询相似。起首是tagstaggins举行了一个inner join,选出tags;然后notes和刚join出的鸠合再做一次left join,获得效果。

其他没有触及东西

这篇文章已够长了,然则实在我们另有很多没有触及的东西,比方:聚合函数及查询(havinggroup by)、模子的考证(validate)、定义钩子(hooks)、索引等等。

这些主题下次再来写写。


推荐阅读
  • 本文详细介绍了使用响应文件在静默模式下安装和配置Oracle 11g的方法。硬件要求包括:内存至少1GB,具体可通过命令`grep -i memtotal /proc/meminfo`进行检查。此外,还提供了详细的步骤和注意事项,确保安装过程顺利进行。 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 本文深入探讨了数据库性能优化与管理策略,通过实例分析和理论研究,详细阐述了如何有效提升数据库系统的响应速度和处理能力。文章首先介绍了数据库性能优化的基本原则和常用技术,包括索引优化、查询优化和存储管理等。接着,结合实际应用场景,讨论了如何利用容器化技术(如Docker)来部署和管理数据库,以提高系统的可扩展性和稳定性。最后,文章还提供了具体的配置示例和最佳实践,帮助读者在实际工作中更好地应用这些策略。 ... [详细]
  • Django框架下的对象关系映射(ORM)详解
    在Django框架中,对象关系映射(ORM)技术是解决面向对象编程与关系型数据库之间不兼容问题的关键工具。通过将数据库表结构映射到Python类,ORM使得开发者能够以面向对象的方式操作数据库,从而简化了数据访问和管理的复杂性。这种技术不仅提高了代码的可读性和可维护性,还增强了应用程序的灵活性和扩展性。 ... [详细]
  • RancherOS 是由 Rancher Labs 开发的一款专为 Docker 设计的轻量级 Linux 发行版,提供了一个全面的 Docker 运行环境。其引导镜像仅 20MB,非常适合在资源受限的环境中部署。本文将详细介绍如何在 ESXi 虚拟化平台上安装和配置 RancherOS,帮助用户快速搭建高效、稳定的容器化应用环境。 ... [详细]
  • 本文首先回顾了MySQL在数据字典方面的发展历程,从MySQL 4.1引入的information_schema数据字典开始,使得用户能够通过标准SQL查询轻松获取系统元数据。在此基础上,深入探讨了MySQL 5.7中SYS模式的架构与应用场景,详细解析了其在性能监控、查询优化等方面的优势与实际应用。 ... [详细]
  • Windows环境下详细教程:如何搭建Git服务
    Windows环境下详细教程:如何搭建Git服务 ... [详细]
  • 多种实现 Windows 定时自动执行任务的专业技巧与方案
    在Windows系统中,实现定时自动执行任务有多种专业技巧和方案。常见的方法包括:使用Windows任务计划程序、开发Windows服务以及利用SQL Server Agent作业。这些方法被广泛应用于各种自动化场景,多数技术人员对此都有所了解。 ... [详细]
  • 掌握PHP框架开发与应用的核心知识点:构建高效PHP框架所需的技术与能力综述
    掌握PHP框架开发与应用的核心知识点对于构建高效PHP框架至关重要。本文综述了开发PHP框架所需的关键技术和能力,包括但不限于对PHP语言的深入理解、设计模式的应用、数据库操作、安全性措施以及性能优化等方面。对于初学者而言,熟悉主流框架如Laravel、Symfony等的实际应用场景,有助于更好地理解和掌握自定义框架开发的精髓。 ... [详细]
  • 在Hive中合理配置Map和Reduce任务的数量对于优化不同场景下的性能至关重要。本文探讨了如何控制Hive任务中的Map数量,分析了当输入数据超过128MB时是否会自动拆分,以及Map数量是否越多越好的问题。通过实际案例和实验数据,本文提供了具体的配置建议,帮助用户在不同场景下实现最佳性能。 ... [详细]
  • MySQL:不仅仅是数据库那么简单
    MySQL不仅是一款高效、可靠的数据库管理系统,它还具备丰富的功能和扩展性,支持多种存储引擎,适用于各种应用场景。从简单的网站开发到复杂的企业级应用,MySQL都能提供强大的数据管理和优化能力,满足不同用户的需求。其开源特性也促进了社区的活跃发展,为技术进步提供了持续动力。 ... [详细]
  • Java 8 引入了 Stream API,这一新特性极大地增强了集合数据的处理能力。通过 Stream API,开发者可以更加高效、简洁地进行集合数据的遍历、过滤和转换操作。本文将详细解析 Stream API 的核心概念和常见用法,帮助读者更好地理解和应用这一强大的工具。 ... [详细]
  • 如何利用Apache与Nginx高效实现动静态内容分离
    如何利用Apache与Nginx高效实现动静态内容分离 ... [详细]
  • 本章节深入探讨了 Webpack 命令的高级功能,涵盖了官方快速入门教程中未涉及的细节。通过实际操作和案例分析,对官方文档进行了详细解读与补充,帮助读者更好地理解和应用这些进阶技巧。 ... [详细]
  • 本文深入探讨了 Spring Cloud 微服务架构中 Gateway 组件的应用,详细介绍了其在实现高效请求路由与过滤方面的关键作用。文章首先从基本配置入手,逐步讲解了如何通过静态路由和动态路由实现灵活的服务访问控制。此外,还特别介绍了如何配置 Gateway 以自动从 Nacos 服务注册中心拉取服务列表,进一步提升系统的可维护性和扩展性。 ... [详细]
author-avatar
钱靖均秀蓉怡慧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有