ORM :對象關(guān)系映射(英語:Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。
O(面向?qū)ο? <-----> ORMapping <-----> R(面向關(guān)系)
在數(shù)據(jù)庫層面, 尤其是關(guān)系型數(shù)據(jù)庫. 是沒有對象概念的.
有的只是表格, 和數(shù)據(jù)記錄
想象一下, 如果你在某個(gè)視頻網(wǎng)站, 為某個(gè)視頻寫了一條評論
接下來會發(fā)生什么呢?
我們要更改用戶表的記錄, 增加評論數(shù)
用SQL語句進(jìn)行操作
update t_user set .......
可是我們平時(shí)都是面向?qū)ο缶幊痰?/p>
從邏輯上講
我們的代碼應(yīng)該是這樣寫的
video.cmmt_cnt++;
這樣就夠了嗎? 當(dāng)然不夠
我們還需要增加評論表
還不止這些
如果這條評論被置頂了呢
如果這條評論對其他人不可見呢?
如果這條評論@了其他人呢
如果這條評論被人點(diǎn)贊了呢
只要稍微增加一點(diǎn)功能, 邏輯都會變得復(fù)雜很多
一個(gè)看似簡單的添加評論, 其實(shí)背后并不簡單
顯然操作數(shù)據(jù)庫, 跟實(shí)現(xiàn)業(yè)務(wù)邏輯采用的思維方式是不同的
一個(gè)是面向關(guān)系, 處理好每張表的變化, 以及表之間的關(guān)聯(lián)
一個(gè)是面向?qū)ο笏季S, 將每一條記錄看做一個(gè)對象去操作
在沒有ORMapping之前, 程序員必須要自己搞定這二者復(fù)雜的關(guān)系轉(zhuǎn)換
而有了ORMapping框架之后
程序員的代碼, 大概就會變成這樣
video.addComment(new Comment(......));
這樣就夠了, 面向?qū)ο蟮拇a, 將自動(dòng)轉(zhuǎn)換成對應(yīng)的SQL語句
更新所有關(guān)聯(lián)的表格
下面簡單介紹一個(gè)nodeJS里面的 ORMapping 框架的使用
sequelize
在nodejs中,有不少ORM模塊,他們各有特點(diǎn),這里的話我們選擇一個(gè)ORM(sequelize)進(jìn)行介紹。
使用流程
1. 在mysql中創(chuàng)建要操作的數(shù)據(jù)庫
2. 安裝ORM模塊:sequelize 與 mysql2
yarn add mysql2 sequelize -S
3. 開始寫nodejs代碼進(jìn)行操作
· 目錄結(jié)構(gòu)
· 根目錄下創(chuàng)建 db.js文件,里面進(jìn)行連接數(shù)據(jù)庫
const Sequelize = require("sequelize")
var DB = new Sequelize(
'w1902-1', // 數(shù)據(jù)庫名
'root', // 用戶名
'123456A', // 用戶密碼
//數(shù)據(jù)庫配置對象
{
'dialect': 'mysql', // 數(shù)據(jù)庫使用mysql
'host': 'localhost', // 數(shù)據(jù)庫服務(wù)器ip
'port': 3306, // 數(shù)據(jù)庫服務(wù)器端口
'define': {
// 字段以下劃線(_)來分割(默認(rèn)是駝峰命名風(fēng)格)
'underscored': true,
'charset': 'utf8',
'collate': 'utf8_general_ci',
'freezeTableName': true,
'timestamps': true, //為模型添加 createdAt 和 updatedAt 兩個(gè)時(shí)間戳字段
},
'pool': { //連接池
'maxConnections': 20,
'minConnections': 0,
'maxIdleTime': 10000 // 連接最大空置時(shí)間(毫秒),超時(shí)后將釋放連接
},
}
);
module.exports = DB;
· 根目錄下創(chuàng)建 model文件夾,表示映射各個(gè)表的模型如model/User.js
// 要定義模型和表之間的映射,請使用define方法。 隨后Sequelize將自動(dòng)添加createdAt和updatedAt屬性。
// 因此,您將能夠知道數(shù)據(jù)庫條目何時(shí)進(jìn)入數(shù)據(jù)庫以及最后一次更新時(shí)。
var Sequelize = require('sequelize');
var DB = require('../DB');
var User = DB.define(
'user', //模型名
{
userId: {
field: 'user_id',
primaryKey: true,
type: Sequelize.BIGINT,
allowNull: false
},
userName: {
field: 'user_name',
type: Sequelize.STRING,
allowNull: false
},
}, {
// 如果為 true 則表的名稱和 model 相同,即 user
// 為 false MySQL創(chuàng)建的表名稱會是復(fù)數(shù) users
// 如果指定的表名稱本就是復(fù)數(shù)形式則不變
freezeTableName: false
}
);
// 創(chuàng)建表
// User.sync() 會創(chuàng)建表并且返回一個(gè)Promise對象
// 如果 force = true 則會把存在的表(如果users表已存在)先銷毀再創(chuàng)建表
// 默認(rèn)情況下 forse = false
User.sync({
force: false
});
// 添加新用戶
module.exports = User;
· 根目錄下創(chuàng)建serve.js文件,在此文件中操作user表
完整代碼
var User = require('./model/User');
//添加(創(chuàng)建)用戶(直接添加)
function create() {
// 添加用戶(直接添加)
User.create({
userId: 38,
userName: '老王2',
}).then(function(user) {
console.log('****************************');
console.log('添加結(jié)果為:', user._options.isNewRecord);
}).catch(function(err) {
console.log("出錯(cuò)了:", err);
});
}
// 添加(創(chuàng)建)用戶 (先查詢在添加)
function findOrCreate() {
// 添加用戶:此方法會先查詢,如果查詢到有此條數(shù)據(jù)相同的就不會新增,返回created:false,得到查詢結(jié)果
User.findOrCreate({
where: {
userId: 38,
userName: '老王9'
}
})
.spread((test, created) => {
if (created == false) {
//說明數(shù)據(jù)已存在,添加失敗
console.log("-------------數(shù)據(jù)已存在,添加失敗--------------");
var data = test.get({
plain: true
});
console.log("已存在的數(shù)據(jù)為:", data);
} else {
console.log("添加成功...");
}
}).catch(function(err) {
console.log("出錯(cuò)了:", err);
})
}
//查詢單條數(shù)據(jù)(根據(jù)任意字段)
function find() {
User.findOne({
where: {
userId: 38
}
})
.then(function(user) {
console.log('****************************');
console.log("查詢的數(shù)據(jù)為:", user.dataValues);
console.log('****************************');
console.log('user userName: ', user.userName);
console.log('user userName: ', user.userId);
});
}
//查詢所有數(shù)據(jù)
function findAll() {
//查詢所有數(shù)據(jù)
User.findAll()
.then(data => {
// 從結(jié)果集中取出所有數(shù)據(jù)
var users = [];
data.forEach(function(ele) {
users.push(ele.dataValues)
})
console.log("所有的數(shù)據(jù)為:", users)
})
}
//刪除數(shù)據(jù)
function destroy() {
User.destroy({
where: {
userId: 38
}
})
.then(function(result) { //表示刪除的數(shù)據(jù)的條數(shù)
console.log('共刪除數(shù)據(jù)條數(shù)為:', result);
});
}
//修改數(shù)據(jù)
function update() {
User.update({
userName: "張三"
}, {
where: {
userId: 36
}
})
.then(function(result) {
console.log('共修改數(shù)據(jù)條數(shù)為:', result);
})
}
//調(diào)用相關(guān)方法
update()
感受一下, 有了ORMapping框架之后, 操作數(shù)據(jù)庫有多簡單