在使用 node-oracledb 6.0 的默認 Thin 模式開發(fā) Node.js 應(yīng)用時,開發(fā)者可能會觀察到一個令人困惑的現(xiàn)象:即使所有數(shù)據(jù)庫操作 seemingly 完成,腳本也不會立即終止,而是會停頓數(shù)秒后才退出。這種延遲尤其在使用 time 命令衡量腳本執(zhí)行時間時表現(xiàn)得非常明顯。
考慮以下 Node.js 腳本,它連接到 Oracle 數(shù)據(jù)庫并執(zhí)行一個簡單的查詢,但有意不關(guān)閉數(shù)據(jù)庫連接:
const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); // 包含數(shù)據(jù)庫連接配置 async function runApp() { let connection; try { connection = await oracledb.getConnection(dbConfig); const result = await connection.execute(`select * from dual`); console.dir(result.rows, { depth: null }); console.log('未關(guān)閉連接'); // 注意:此處 connection.close() 被注釋掉 } catch (err) { console.error(err); } finally { // 即使在 finally 塊中,如果 connection.close() 被注釋,問題依然存在 // if (connection) { // try { // await connection.close(); // console.log('連接已關(guān)閉'); // } catch (err) { // console.error(err); // } // } } } runApp();
當(dāng)我們在 Linux 環(huán)境下使用 time 命令運行上述腳本時,會發(fā)現(xiàn)明顯的延遲:
$ time node t.js [ [ 'X' ] ] 未關(guān)閉連接 real 0m8.187s # 實際執(zhí)行時間長達8秒多 user 0m0.092s sys 0m0.017s
然而,如果我們將 await connection.close() 取消注釋,顯式關(guān)閉連接:
const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); async function runApp() { let connection; try { connection = await oracledb.getConnection(dbConfig); const result = await connection.execute(`select * from dual`); console.dir(result.rows, { depth: null }); console.log('正在關(guān)閉連接'); await connection.close(); // 顯式關(guān)閉連接 console.log('連接已關(guān)閉'); } catch (err) { console.error(err); } finally { // 在實際應(yīng)用中,通常會在 finally 塊中確保連接關(guān)閉 // if (connection) { // try { // await connection.close(); // } catch (err) { // console.error(err); // } // } } } runApp();
再次運行,延遲便會消失:
$ time node t.js [ [ 'X' ] ] 正在關(guān)閉連接 連接已關(guān)閉 real 0m0.249s # 實際執(zhí)行時間恢復(fù)正常 user 0m0.082s sys 0m0.017s
在 node-oracledb 的早期版本或使用 Thick 模式時,即使不顯式關(guān)閉連接,也通常不會出現(xiàn)這種延遲。
這種行為上的差異源于 node-oracledb 6.0 Thin 模式與 Thick 模式(或早期版本)在底層網(wǎng)絡(luò)資源管理方式上的根本不同。
Thin 模式的工作原理: 在 node-oracledb 6.0 的 Thin 模式中,該模塊直接管理與 Oracle 數(shù)據(jù)庫建立的網(wǎng)絡(luò)套接字(sockets)。這些套接字是 Node.js 事件循環(huán)已知的資源。這意味著,只要這些套接字處于打開狀態(tài),Node.js 的事件循環(huán)就會認為仍有待處理的 I/O 操作,從而阻止應(yīng)用程序立即終止。 當(dāng)沒有顯式調(diào)用 connection.close() 時,這些套接字會保持打開狀態(tài)。Node.js 內(nèi)部有一個“終結(jié)注冊表”(finalization registry)機制,它會在持有這些套接字的對象被 JavaScript 垃圾回收器回收時,強制關(guān)閉這些套接字。然而,垃圾回收的時機是不可預(yù)測的,這正是導(dǎo)致腳本在執(zhí)行完畢后出現(xiàn)數(shù)秒不確定延遲的原因。應(yīng)用程序必須等待垃圾回收器介入并清理這些資源后,Node.js 進程才能最終退出。
Thick 模式(或早期版本)的工作原理: 與 Thin 模式不同,在 Thick 模式下或 node-oracledb 的早期版本中,底層的網(wǎng)絡(luò)連接和套接字是由外部的 Oracle 客戶端庫(Oracle Client library)管理的。這個客戶端庫通常是一個 C/C++ 庫,它在 Node.js 進程之外維護這些資源。 對于 Node.js 運行時而言,它對這些由外部庫管理的套接字一無所知,也不會將它們視為需要保持事件循環(huán)活躍的因素。因此,當(dāng) Node.js 腳本中的所有 JavaScript 異步操作完成后,即使 Oracle 客戶端庫內(nèi)部的連接尚未完全關(guān)閉,Node.js 也會認為其事件循環(huán)已空閑,從而愉快地終止進程,不會出現(xiàn)額外的延遲。
理解了背后的機制,解決方案就變得非常明確:始終顯式關(guān)閉數(shù)據(jù)庫連接。
通過調(diào)用 await connection.close(),我們指示 node-oracledb 立即釋放與該連接關(guān)聯(lián)的所有底層網(wǎng)絡(luò)資源。這會通知 Node.js 事件循環(huán),相關(guān)的 I/O 操作已完成,并且沒有未決的網(wǎng)絡(luò)活動需要等待。一旦所有連接都被顯式關(guān)閉,Node.js 進程便能立即判斷事件循環(huán)已空閑,從而快速終止。
推薦的代碼結(jié)構(gòu):
const oracledb = require('oracledb'); const dbConfig = require('./dbconfig.js'); async function runApp() { let connection; // 聲明 connection 變量 try { connection = await oracledb.getConnection(dbConfig); const result = await connection.execute(`select * from dual`); console.dir(result.rows, { depth: null }); console.log('數(shù)據(jù)庫操作完成'); } catch (err) { console.error('執(zhí)行數(shù)據(jù)庫操作時發(fā)生錯誤:', err); } finally { // 確保無論是否發(fā)生錯誤,連接都會被關(guān)閉 if (connection) { try { await connection.close(); console.log('數(shù)據(jù)庫連接已安全關(guān)閉。'); } catch (err) { console.error('關(guān)閉數(shù)據(jù)庫連接時發(fā)生錯誤:', err); } } } } runApp();
注意事項:
node-oracledb 6.0 Thin 模式下腳本結(jié)束時的延遲是其底層網(wǎng)絡(luò)資源管理機制的預(yù)期行為。由于 Thin 模式直接管理網(wǎng)絡(luò)套接字并將其注冊到 Node.js 事件循環(huán)中,這些未關(guān)閉的套接字會阻止進程立即終止。通過在代碼中顯式調(diào)用 await connection.close(),開發(fā)者可以確保網(wǎng)絡(luò)資源及時釋放,從而實現(xiàn)腳本的即時終止,并遵循數(shù)據(jù)庫連接管理的最佳實踐。這一改變強調(diào)了在現(xiàn)代 Node.js 數(shù)據(jù)庫驅(qū)動中,對資源生命周期進行精確控制的重要性。
以上就是解決 node-oracledb 6.0 Thin 模式腳本結(jié)束延遲問題的詳細內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進程會占用資源并降低性能。幸運的是,許多工具可以讓 Windows 保持平穩(wěn)運行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號