Node.js數(shù)據(jù)庫鉤子的使用
在本文中,我將解釋如何在您的Node.js應(yīng)用程序中使用數(shù)據(jù)庫鉤子來解決在開發(fā)過程中可能出現(xiàn)的特定問題。
許多應(yīng)用程序只需要在服務(wù)器、數(shù)據(jù)庫之間建立連接池并執(zhí)行查詢。然而,根據(jù)您的應(yīng)用程序和數(shù)據(jù)庫部署情況,可能需要進(jìn)行其他配置。
例如,多區(qū)域分布式SQL數(shù)據(jù)庫可以根據(jù)應(yīng)用程序用例的不同拓?fù)溥M(jìn)行部署。某些拓?fù)湫枰诿總€會話中在數(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ù)庫進(jìn)行調(diào)用之前或之后立即執(zhí)行函數(shù)。
在本文中,我將介紹這些客戶端提供的一些鉤子,并說明您如何在分布式SQL應(yīng)用程序中使用它們的好處。
我還將演示如何在創(chuàng)建用戶之前使用鉤子對用戶的密碼進(jìn)行散列,并在連接到具有讀副本的多區(qū)域數(shù)據(jù)庫后如何設(shè)置運(yùn)行時配置參數(shù)。
Sequelize
Sequelize ORM提供了許多鉤子來管理數(shù)據(jù)庫事務(wù)的整個生命周期。
beforeCreate生命周期鉤子可用于在創(chuàng)建新用戶之前對密碼進(jìn)行散列處理:
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)建用戶之前對密碼進(jìn)行哈希處理的方法:
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顯式地進(jìn)行連接,而不使用連接池的延遲連接。
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)中進(jìn)行查詢調(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中的查詢中間件。
要對密碼進(jìn)行哈希處理,可以使用自定義函數(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ā)連接事件。
當(dāng)在連接池中建立新連接時,會觸發(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一樣,我們必須手動進(jìn)行密碼哈希處理:
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)在,當(dāng)那一天來臨時,請準(zhǔn)備就緒。
到此這篇關(guān)于Node.js數(shù)據(jù)庫鉤子的使用的文章就介紹到這了,更多相關(guān)Node.js數(shù)據(jù)庫鉤子內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node.js實現(xiàn)大文件斷點續(xù)傳示例詳解
這篇文章主要為大家介紹了Node.js實現(xiàn)大文件斷點續(xù)傳示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11利用nodejs讀取圖片并將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成base64格式
這篇文章主要介紹了利用nodejs讀取圖片并將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成base64格式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08node.js從數(shù)據(jù)庫獲取數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了node.js從數(shù)據(jù)庫獲取數(shù)據(jù)的具體代碼,nodejs可以獲取具體某張數(shù)據(jù)表信息,感興趣的朋友可以參考一下2016-05-05Windows安裝Node.js報錯:2503、2502的解決方法
這篇文章主要給大家介紹了關(guān)于在Windows系統(tǒng)下安裝Node.js報錯:2503、2502的解決方法,文中將解決的方法一步步介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10