現在NodeでORACLEからデータを取得する処理を実装しようとしているのですが、
下記のコードを試してもexecute内では値が取れるのですがデータを持ちまわる事が
出来ません。どうすれば持ちまわれますか?
Node.js
1var oracledb = require("oracledb"); 2 3module.exports = { 4 Syain_Select: function (SYAIN_CD) { 5 let sql = "select * from SYAIN_TB"; 6 let res = ""; 7 8 oracledb.getConnection( 9 { 10 connectString: "IP", 11 user: "USER", 12 password: "PASS", 13 }, 14 function (err, conn) { 15 if (err) { 16 console.error(err.message); 17 return; 18 } 19 conn.execute(sql, function (err, results, req) { 20 res = results.rows[0]; 21 conn.close(); 22 }); 23 } 24 ); 25 console.log(res); 26 } 27};
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
データを持ちまわる事が出来ません。どうすれば持ちまわれますか?
基本的には出来ませんよ、
なので諦めてMr.ドリラーのように処理終了まで掘り続けてください。
でもまぁ、コールバック関数の使い方をしっかり覚えれば、
こんなに掘りまくらなくてもコールバック関数を要求する関数を上手く作ってハンドリング出来るので、Node.js力が身につけば自然と解決出来るでしょう。
Promiseやasync/awaitもその一環ですので、Node.jsを使い続けるならこれらの機能をちゃんと勉強して使いこなせるようにしてください。
これがベースです。
しかし、これが本筋じゃなさそうですね。
なのでちゃーんとデータを持ちまわる必殺技を覚える必要があるでしょう。
当然難解ですので、頑張って付いてきて下さいね。
代表的な手法は下記の2通りの組み合わせです。
- 親スコープからオブジェクトや配列等を渡してやる
- EventEmitterを覚える
このいずれか、または両方を組み合わせて実現させます。
EventEmitterは結構難解ですが、覚えなくても大丈夫です(理由は後述)
というわけで「親スコープからオブジェクトや配列等を渡してやる」を解説していきます。
まず、JavaScriptの変数の値はプリミティブ値かオブジェクトかの二択です。
この内、オブジェクトはメモリ空間のアドレス値を使い、その実体はどこからでもアクセス出来るので、関数の引数や戻り値として別のものに手渡したとしても普通に中身にアクセスして読み書きが出来ます。
JavaScript
1const user = { 2 name: 'taro', 3 age: 18 4} 5const main = he => { 6 console.log(he.name) // taro 7 he.sex = 'male' 8 return he 9} 10const user2 = main(user) 11 12console.log(user) // {name: "taro", age: 18, sex: "male"} 13console.log(user2) // {name: "taro", age: 18, sex: "male"}
このように、userは引数としてmain関数の中に突っ込んだだけなのに、
内部の関数でheを変更した余波がそのまま反映されましたね。
これを利用して値を取り出す事が出来ます。
この時、userの中身が数値や文字列等のプリミティブ値の場合は絶対に実現出来ませんし、
オブジェクトを渡したとしても関数の中でhe = {}
のように代入をした場合、メモリ空間上の参照アドレス値が吹っ飛んで値が取り出せなくなりますので、
he.hoge = 123
等のように、必ず内部のキー情報にアクセスしながら代入するようにしてください。
では、質問文のコードを軸にoracleから値を吸い出すロジックを考えていきましょう。
元々のコードはちょっと手直ししてこんな感じですかね。
JavaScript
1// 仮にoracle.jsとする 2const oracledb = require("oracledb"); 3 4module.exports = { 5 // 引数にオブジェクトを要求する 6 Syain_Select: function (state) { 7 const {SYAIN_CD} = state; // 元々の引数予定だったSYAIN_CDはstate内へ引っ越し 8 let sql = "select * from SYAIN_TB"; 9 let res = ""; 10 11 oracledb.getConnection( 12 { 13 connectString: "IP", 14 user: "USER", 15 password: "PASS", 16 }, 17 function (err, conn) { 18 if (err) { 19 console.error(err.message); 20 return; 21 } 22 conn.execute(sql, function (err, results, req) { 23 res = results.rows[0]; 24 state.response = res; // ここでstateに保存! 25 conn.close(); 26 }); 27 } 28 ); 29 } 30};
続いて使う側です。
JavaScript
1const oracle = require('./oracle.js'); 2const state = {}; // 状態を意味するオブジェクトを宣言しておく 3 4state.SYAIN_CD = '123456'; // 検索に利用するはずだった社員コードがstate内に引っ越したのでここに格納 5 6oracle.Syain_Select(state); // 実行 7 8// JSは非同期処理を実行すると了解といってすぐ戻ってくるのでresultにはアクセス出来ない 9console.log(state); // {SYAIN_CD: '123456'} 10 11// なので待つ 12const wait = () => { 13 console.log(state); 14 if (state.result) return 15 setTimeout(wait, 3000); 16}
なんか微妙だなぁ…といった感じですが、この技法単体ではこんなもんです。
待てば結果が返って来て取得出来るだけなので御の字でしょう。
嫌ならコールバック関数で全部数珠つなぎにして頑張ってください。
次の章はEventEmitterと併用して使えない子からステップアップを目指します。
次にNode.jsを使って何を表現したいのでしょうか?
それによりアドバイスが変わります。
- Expressを使ってWebサイトを構築したい
- WebSocketを使ってWSサーバを構築したい
Node.jsを扱う動機で多いのは、このどちらかでしょう。
コイツらはEventEmitterの機能が搭載されているので、覚える必要がないと言ったのはそういう理由からです。
これらとは関係なく実現させたければ自分でEventEmitterを覚えて使いこなせるようにしてください。
今回はExpressとの併用を紹介しますので、WS目当てなら参考に頑張ってください。
まずは、サーバーを公開する前にDBにアクセスして置かなければならないモノを取得します。
JavaScript
1const require('oracle.js'); 2const state = {}; 3 4const express = require('express'); 5const app = express(); 6app.get('/', (req, res) => { 7 res.json(state.result); 8}) 9 10// Webサーバは80番ポートで待ち受けなければ誰もアクセス出来ないので、結果が取れるまでせき止める 11const wait = () => { 12 if (!state.result) { 13 return setTimeout(wait, 1000); 14 } 15 app.listener(80); 16 console.log('get ready'); 17}
これでget readyがコンソール上に表示されてからアクセスすれば、
httpアクセスすると社員情報が返ってきます。
いや、社員コードは動的にアクセスしたいんだが
しょうがない、やっぱりコールバック関数に関するあたりの説明も必要ですね…
今回はNoderらしい方法でやっていきます。
まず、OracleのコネクションはWebサーバが毎回切断するのはアホです。
張りっぱなしが当然です。
なので関数を分けて張りっぱなしに出来るようstateオブジェクト内に保存し続ける作りにします。
各関数の引数にコールバック関数という引数を用意して要求するようにします。
この時、他のコールバック関数を引数に取る関数は、全て最終引数が該当するのでそれに合わせます。
JavaScript
1// oracle2.js 2const oracledb = require("oracledb"); 3 4module.exports = { 5 getConn: function (cb) { 6 oracledb.getConnection({ 7 connectString: "IP", 8 user: "USER", 9 password: "PASS", 10 }, cb); 11 }, 12 Syain_Select: function (conn, SYAIN_CD, cb) { 13 // TODO: ここ入力値がそのままSQL文になってる可能性があるのでエスケープ作っておいてください 14 let sql = `select * from SYAIN_TB where SYAIN_CB = '${SYAIN_CB}'`; 15 conn.execute(sql, cb); 16 } 17};
こんな殺風景で大丈夫か?
これが最善です、結果を受け取った側が今後の動作を考えるべきなので、
こいつらがする事はシンプルな事にとどめましょう。
続いてExpressです。
JavaScript
1const oracle = require('./oracle2.js'); 2const state = {}; // いつものやつ 3 4const express = require('express'); 5const app = express(); 6app.get('/:code', (req, res) => { 7 const code = req.params.code 8 oracle.Syain_Select(state.conn, code, (err, results, req) => { 9 if (err) { 10 // 社員番号が取れなかったみたいな感じで 11 res.status(400).json(err.message); 12 return; 13 } 14 res.json(results.row); 15 }); 16}) 17 18oracle.getConn((err, conn) => { 19 if (err) throw err; // Oracleに接続出来なければサーバーは起動できない 20 state.conn = conn; // getConnから持ち帰ってきたconnを保存 21 app.listen(80); // サーバを起動 22 console.log('get ready.'); 23})
ちょっと知恵の輪みたいに複雑でしたが、Node.jsではこのような流れで必要な値を適宜外のスコープに持ち帰りながらサーバを構築する必要があります。
ゆっくり読み返しながら反芻していってください。
処理が増えると長い直列の非同期処理が必要な事もあるかと思います。
どんどんネストが深くなっていきコードがカオスになっていきます。
ファイルを区切って抽象化したり、Promiseやasync/awaitの構文を覚えて管理出来るように学習してください。
それでは良きNode.jsライフを
投稿2018/04/12 13:18
総合スコア21158
0
Node.jsはノンブロッキングI/Oなので、非同期処理で取得した値を別の箇所で使用する場合はPromiseやasync/awaitを使いましょう。
Promise: https://qiita.com/toshihirock/items/e49b66f8685a8510bd76
async/await: https://qiita.com/Anders/items/dfcb48d8b27ceaffb443
投稿2018/04/12 10:37
総合スコア1679
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
callbackのみでDB操作は現実的ではありません。
node-oracledbはPromise化されているのでPromiseでがんばります。
https://oracle.github.io/node-oracledb/doc/api.html#promiseoverview
Promiseならばasync/await構文にもすぐに書き直せます。
上記URLのサンプルはこんな感じで書けます。
エラー処理はPromise.catchやtry-catchで挙動を確認しながら勉強してみてください。
突破口となれば幸いです。
js
1const oracledb = require('oracledb'); 2 3(async ()=>{ 4 const conn = await oracledb.getConnection({ 5 user : "hr", 6 password : "welcome", 7 connectString : "localhost/XE" 8 }); 9 const result = await conn.execute( 10 `SELECT department_id, department_name 11 FROM departments 12 WHERE manager_id < :id`, 13 [110] // bind value for :id 14 ); 15 console.log(result); 16})()
投稿2018/04/13 09:13
総合スコア764
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。