Node.js數(shù)據(jù)庫鉤子的使用
在本文中,我將解釋如何在您的Node.js應(yīng)用程序中使用數(shù)據(jù)庫鉤子來解決在開發(fā)過程中可能出現(xiàn)的特定問題。
許多應(yīng)用程序只需要在服務(wù)器、數(shù)據(jù)庫之間建立連接池并執(zhí)行查詢。然而,根據(jù)您的應(yīng)用程序和數(shù)據(jù)庫部署情況,可能需要進行其他配置。
例如,多區(qū)域分布式SQL數(shù)據(jù)庫可以根據(jù)應(yīng)用程序用例的不同拓撲進行部署。某些拓撲需要在每個會話中在數(shù)據(jù)庫上設(shè)置屬性。
讓我們探索一下Node.js生態(tài)系統(tǒng)中一些最受歡迎的數(shù)據(jù)庫客戶端和ORM提供的一些鉤子。
基礎(chǔ)
在使用最流行的關(guān)系數(shù)據(jù)庫時,Node.js社區(qū)有許多可供選擇的驅(qū)動程序。在這里,我將重點關(guān)注與兼容PostgreSQL的數(shù)據(jù)庫客戶端,它們可以用于連接到Y(jié)ugabyteDB或其他PostgreSQL數(shù)據(jù)庫。
Sequelize、Prisma、Knex和node-postgres是一些功能各異的受歡迎的客戶端,具體取決于您的需求。我鼓勵您閱讀它們的文檔,以確定哪個最適合您的需求。
這些客戶端提供了不同用例的鉤子。例如:
- 連接鉤子: 在連接和斷開與數(shù)據(jù)庫的連接之前或之后立即執(zhí)行函數(shù)。
- 日志鉤子: 在不同的日志級別下將消息記錄到stdout。
- 生命周期鉤子: 在對數(shù)據(jù)庫進行調(diào)用之前或之后立即執(zhí)行函數(shù)。
在本文中,我將介紹這些客戶端提供的一些鉤子,并說明您如何在分布式SQL應(yīng)用程序中使用它們的好處。
我還將演示如何在創(chuàng)建用戶之前使用鉤子對用戶的密碼進行散列,并在連接到具有讀副本的多區(qū)域數(shù)據(jù)庫后如何設(shè)置運行時配置參數(shù)。
Sequelize
Sequelize ORM提供了許多鉤子來管理數(shù)據(jù)庫事務(wù)的整個生命周期。
beforeCreate生命周期鉤子可用于在創(chuàng)建新用戶之前對密碼進行散列處理:
User.beforeCreate(async (user, options) => {
const hashedPassword = await hashPassword(user.password);
user.password = hashedPassword;
});接下來,我使用afterConnect連接鉤子來設(shè)置會話參數(shù)。
通過這個YugabyteDB部署,您可以從跟隨者執(zhí)行讀取操作以減少延遲,并且無需從主集群節(jié)點讀取:
const config = {
? host: process.env.DB_HOST,
? port: 5433,
? dialect: "postgres",
? dialectOptions: {
? ? ssl: {
? ? ? require: true,
? ? ? rejectUnauthorized: true,
? ? ? ca: [CERTIFICATE],
? ? },
? },
? pool: {
? ? max: 5,
? ? min: 1,
? ? acquire: 30000,
? ? idle: 10000,
? },
? hooks: {
? ? ?async afterConnect(connection) {
? ? ? ?if (process.env.DB_DEPLOYMENT_TYPE === "multi_region_with_read_replicas") {
? ? ? ? ?await connection.query("set yb_read_from_followers = true; set session characteristics as transaction read only;");
? ? ? ?}
? ? ?},
? ?},
};
const connection = new Sequelize(
? ?process.env.DATABASE_NAME,
? ?process.env.DATABASE_USER,
? ?process.env.DATABASE_PASSWORD,
? ?config
);通過使用這個鉤子,在連接池中的每個數(shù)據(jù)庫會話在建立新連接時都會設(shè)置這些參數(shù):
- set yb_read_from_followers = true;:此參數(shù)控制是否啟用從跟隨者讀取。
- set session characteristics as transaction read only;:此參數(shù)將只讀設(shè)置應(yīng)用于后續(xù)的所有語句和事務(wù)塊。
Prisma
盡管在Node.js社區(qū)中,Prisma是許多人首選的ORM,但在撰寫本文時,Prisma并不包含Sequelize中的許多內(nèi)置鉤子。目前,該庫包含用于處理查詢生命周期、日志記錄和斷開連接的鉤子,但在建立連接之前或之后提供的幫助很少。
以下是如何使用Prisma的生命周期中間件在創(chuàng)建用戶之前對密碼進行哈希處理的方法:
prisma.$use(async (params, next) => {
?if (params.model == 'User' && params.action == 'create') {
? ?params.args.data.password = await hashPassword(params.args.data.password);
?}
?return next(params)
})
const create = await prisma.user.create({
?data: {
? ?username: 'bhoyer',
? ?password: 'abc123'
?},
})要設(shè)置會話參數(shù)以利用我們的讀取副本,我們需要在查詢數(shù)據(jù)庫之前執(zhí)行一條語句:
await prisma.$executeRaw(`set yb_read_from_followers = true; set session characteristics as transaction read only;`); const users = await prisma.user.findMany();
如果您需要立即在連接池中建立連接以設(shè)置參數(shù),您可以使用Prisma顯式地進行連接,而不使用連接池的延遲連接。
Prisma具有查詢(query)、錯誤(error)、信息(info)和警告(warn)等日志級別??梢允褂没谑录娜罩居涗泚硖幚聿樵兪录?/p>
const prisma = new PrismaClient({
?log: [
? ?{
? ? ?emit: 'event',
? ? ?level: 'query',
? ?},
? ?{
? ? ?emit: 'stdout',
? ? ?level: 'error',
? ?},
? ?{
? ? ?emit: 'stdout',
? ? ?level: 'info',
? ?},
? ?{
? ? ?emit: 'stdout',
? ? ?level: 'warn',
? ?},
?],
});
prisma.$on('query', (e) => {
?console.log('Query: ' + e.query);
?console.log('Params: ' + e.params);
?console.log('Duration: ' + e.duration + 'ms');
});這在開發(fā)過程中對于在分布式系統(tǒng)中進行查詢調(diào)優(yōu)非常有幫助。
下面是如何在退出之前使用beforeExit鉤子來訪問數(shù)據(jù)庫的示例:???????
const prisma = new PrismaClient();
prisma.$on('beforeExit', async () => {
?// PrismaClient still available
?await prisma.issue.create({
? ?data: {
? ? ?message: 'Connection exiting.'?
? ?},
?})
});Knex是一個輕量級的查詢構(gòu)建器,但它沒有更全功能的ORM中的查詢中間件。
要對密碼進行哈希處理,可以使用自定義函數(shù)來手動處理:
async function handlePassword(password) {
const hashedPassword = await hashPassword(password);
return hashedPassword;
}
const password = await handlePassword(params.password);
knex('users').insert({...params, password});在Knex.js查詢構(gòu)建器中實現(xiàn)連接鉤子所需的語法與Sequelize類似。以下是如何設(shè)置會話參數(shù)以從YugabyteDB的副本節(jié)點讀取的示例代碼:
const knex = require('knex')({
client: 'pg',
connection: {/*...*/},
pool: {
afterCreate: function (connection, done) {
connection.query('set yb_read_from_followers = true; set session characteristics as transaction read only;', function (err) {
if (err) {
//Query failed
done(err, conn);
} else {
console.log("Reading from replicas.");
done();
}
});
}
}
});node-postgres庫是所有討論過的庫中最低級的庫。在底層,使用Node.js的EventEmitter來觸發(fā)連接事件。
當在連接池中建立新連接時,會觸發(fā)connect事件。我們可以使用它來設(shè)置我們的會話參數(shù)。我還添加了一個錯誤鉤子來捕獲和記錄所有錯誤消息的示例代碼:???????
const config = {
? user: process.env.DB_USER,
? host: process.env.DB_HOST,
? password: process.env.DB_PASSWORD,
? port: 5433,
? database: process.env.DB_NAME,
? min: 1,
? max: 10,
? idleTimeoutMillis: 5000,
? connectionTimeoutMillis: 5000,
? ssl: {
? ? rejectUnauthorized: true,
? ? ca: [CERTIFICATE],
? ? servername: process.env.DB_HOST,
? }
};
const pool = new Pool(config);
pool.on("connect", (c) => {
? c.query("set yb_read_from_followers = true; set session characteristics as transaction read only;");
});
pool.on("error", (e) => {
? console.log("Connection error: ", e);
});在node-postgres中,我們沒有可用的生命周期鉤子,所以像Prisma一樣,我們必須手動進行密碼哈希處理:
async function handlePassword(password) {
const hashedPassword = await hashPassword(password);
return hashedPassword;
}
const password = await handlePassword(params.password);
const user = await pool.query('INSERT INTO user(username, password) VALUES ($1, $2) RETURNING *', [params.username, password]);總結(jié)
正如你所看到的,鉤子可以解決之前由復(fù)雜且容易出錯的應(yīng)用程序代碼所引起的許多問題。每個應(yīng)用程序都有不同的要求和面臨新的挑戰(zhàn)。在你的開發(fā)過程中,可能會經(jīng)過很多年才需要使用特定的鉤子,但現(xiàn)在,當那一天來臨時,請準備就緒。
到此這篇關(guān)于Node.js數(shù)據(jù)庫鉤子的使用的文章就介紹到這了,更多相關(guān)Node.js數(shù)據(jù)庫鉤子內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用NODE.JS創(chuàng)建一個WEBSERVER(服務(wù)器)的步驟
在 node.js 中創(chuàng)建一個服務(wù)器非常簡單,只需要使用 node.js 為我們提供的 http 模塊及相關(guān) API 即可創(chuàng)建一個麻雀雖小但五臟俱全的web 服務(wù)器,相比 Java/Python/Ruby 搭建web服務(wù)器的過程簡單的很。本文簡單的講解下實現(xiàn)步驟2021-06-06
在Node.js中使用Express框架和Mongoose庫實現(xiàn)視頻評論功能
本文我們將詳細介紹如何在Node.js應(yīng)用中使用Express框架和Mongoose庫來實現(xiàn)一個視頻評論功能,這個功能允許用戶對視頻內(nèi)容添加評論,并將評論數(shù)實時更新,以下是逐步的實現(xiàn)過程,包括代碼示例和說明,需要的朋友可以參考下2024-04-04
Node.js如何快速導(dǎo)出多表頭的excel文件實現(xiàn)方法
這篇文章主要為大家介紹了Node.js如何快速導(dǎo)出多表頭的excel文件實現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
Node.js數(shù)據(jù)流Stream之Readable流和Writable流用法
這篇文章介紹了Node.js數(shù)據(jù)流Stream之Readable流和Writable流的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07

