質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

2回答

1261閲覧

PostgreSQLに9個目以降データが挿入されなくなる

AGLAAGLA

総合スコア54

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

0クリップ

投稿2021/12/20 14:43

編集2021/12/21 01:49

前提・実現したいこと

ラズベリーパイからHTTP通信でダミーデータを送信しPostgreSQLに値を挿入したいと考えています。
現在の状況は9個目までデータベースに格納しているのですが、9個目以降なんのエラーもなく急にデータがデーベースに格納されなくなります。

わかっていることは
client.release()の部分が原因ということはわかっているのですが、clientをどうすれば再帰的にずっとデータベースに格納できるかわかりません。
そしてなぜ9個目で止まるのでしょうか。
エラーログがないので解決できず困っています。
2時間ほど試行錯誤しましたが、解決に至らず、教えていただければ光栄です。

コマンドの出力

Client Request > {"time": "2021-12-20 23:27:52.581135", "sensor": 1,"smell": 10} 接続完了 Result { command: 'INSERT', rowCount: 1, oid: 0, rows: [], fields: [], _parsers: undefined, _types: TypeOverrides { _types: { getTypeParser: [Function: getTypeParser], setTypeParser: [Function: setTypeParser], arrayParser: [Object], builtins: [Object] }, text: {}, binary: {} }, RowCtor: null, rowAsArray: false } 上記の出力が9個終わった後↓ POST "Python-urllib/3.9" Client Request > {"time": "2021-12-20 23:27:57.612159", "sensor": 1,"smell": 10} 接続完了 POST "Python-urllib/3.9" Client Request > {"time": "2021-12-20 23:28:02.756899", "sensor": 1, "smell": 10} POST "Python-urllib/3.9" Client Request > {"time": "2021-12-20 23:28:07.786376", "sensor": 1,"smell": 10} POST "Python-urllib/3.9" Client Request > {"time": "2021-12-20 23:28:12.810994", "sensor": 1,"smell": 10} ^C

該当のソースコード

Javascript

1require('pg').defaults.ssl = true; 2const { Pool } = require('pg') 3process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 4 5const pool = new Pool({ 6 user: '', 7 host: '', 8 database: '', 9 password: '', 10 port: 5432, 11 12}) 13 14 15 16// 通信に必要なライブラリを読み込み 17var http = require('http'); 18 19// HTTPサーバの実行 20var server = http.createServer(); 21 22//SQL接続 23async function postgresql_connect(senserid,smell){ 24 const sqltime="SET TIME ZONE 'Asia/Tokyo'" 25 const sql = "INSERT INTO sensor (time,place,conges) VALUES (current_timestamp, $1, $2)" 26 const values = [senserid, smell] 27 const client = await pool.connect() 28 try { 29 pool 30 .connect() 31 .then(() => console.log("接続完了")) 32 .then(() => pool.query(sqltime)) 33 .then(() => pool.query(sql, values)) 34 .then(result => console.log(result)) 35 .catch((err => console.log(err))) 36 37 38 } finally { 39 client.release() 40 } 41} 42 43 44// サーバにHTTPリクエストが届いたときのコールバック関数 45server.on('request', function(req,res){ 46 // ラズパイからのアクセスがPOSTであった場合 47 if(req.method == 'POST'){ 48 // ラズパイへ返信するデータのヘッダを作成 49 res.writeHead(200, {'Content-Type' : req.headers['content-type']}); 50 51 // ラズパイからデータを受信したときの処理 (コールバック関数) 52 req.on('data', function(data){ 53 54 55 json_data = JSON.parse(data); 56 var smell = json_data.smell; 57 58 postgresql_connect(senserid,smell); 59 60 61 62 // ラズパイから受信したデータ(文字列)を、文字列に変換(受信ログ用) 63 var text = data.toString('utf8'); 64 // データの入力履歴をラズパイに返信 65 res.write('Successfully Received > ' + text); 66 67 68 69 // 受信ログを表示 70 console.log(req.method + ' "' + req.headers['user-agent'] + '"'); 71 console.log('Client Request > ' + data); 72 73 74 }); 75 76 // ラズパイから全てのデータを受信したときの処理(コールバック関数) 77 req.on('end', function(){ 78 // ラズパイへのデータの返信を終了 79 res.end(); 80 }); 81 82 } 83 // ラズパイからのアクセスがPOST以外の場合 84 else { 85 res.writeHead(200, {'Content-Type': 'text/plain'}); 86 res.write('Hello World\n'); 87 res.end(); 88 } 89}); 90 91// ラズパイからの接続を待ち受けるポート番号の設定 92server.listen(8080); 93 94

------------追記----------------
コネクションプールはデフォルトで最大10回ほどしか接続できず、再接続が必要とのことまでは理解しました。
しかし、

finally { client.release() }

でなぜ再接続できないのでしょうか。
ずっと調べ続けても9個以上挿入できず、非常に困っています。
https://teratail.com/questions/253479
こちらで同じような質問をされていましたが、done();では実装できませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

FKM

2021/12/21 00:44

テーブルの設定に問題がありそうです。何を主キーにしていますか?
AGLAAGLA

2021/12/21 00:52

コメントありがとうございます。 まったく一向に進まず悩んでおりました。 私のテーブルの場合、IDをプライマリキー として設定しております。
FKM

2021/12/21 00:53

では、そのIDの型と桁数をどう設定していますか?
AGLAAGLA

2021/12/21 01:09 編集

id serial PRIMARY KEYで定義しております。 私の認識では、 const sql = "INSERT INTO sensor (time,place,conges) VALUES (current_timestamp, $1, $2)" const values = [senserid, smell] として挿入しております。 自動でIDを割り振ってくれると思い、INSERT文では表記しなくていいと思っております。 ここがダメな点なのでしょうか。
FKM

2021/12/21 01:15

seialってことはcreate sequence文で型と桁設定しているはずですが、そのsql文を提示してもらっていいですか?
AGLAAGLA

2021/12/21 01:20 編集

CREATE TABLEの CREATE TABLE sensor (id serial PRIMARY KEY, time timestamp, place INTEGER not null, conges Real not null); 以降、型と桁設定をした覚えはないのですが、、 それが問題点なのでしょうか。
FKM

2021/12/21 01:27

主キーの設定に制約がかかってないかの検証です。明示的にidを99としてデータを入力できるか確かめてみてください。
AGLAAGLA

2021/12/21 01:35

IDは105ほどまでデータを挿入できていたので、恐らく大丈夫だと思います。 毎回、ラズパイから送るたびにテーブルの中身をリセットして行っているのですが、 リセットするたびに値が加わっていくのが少し心配な点です。 (例: 1回目9個目までしか挿入できてない→テーブルの行削除 →二回目 の9個の値を挿入するとIDが9から18になる。次行削除して挿入するとIDが18~27になる→これを繰り返して行って105ほどまで行きました)
FKM

2021/12/21 01:42

なるほど、だとするとネットワークの方の問題っぽいですね。 postgreSQLは一度アボートするとコミットしないと再度クエリ発行できないですが、それは 関係しているでしょうか。 自分が思い当たるのはこれぐらいになりそうです。力になれなくて済みません。
AGLAAGLA

2021/12/21 01:47

client.release()の部分を変更すると、挿入回数が4回になったり変動するのでここが問題なのかと思います。 お手数おかけしました。 こちらこそご丁寧にありがとうございました。
guest

回答2

0

javascript

1 const client = await pool.connect() 2 try { 3 pool 4 .connect()

見当違いかもしれませんが、2回connect()しているのが気になりました。
clientかpoolどちらかだけにしてみたらどうでしょうか?

投稿2021/12/21 04:42

gtakat

総合スコア206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi-sun

2021/12/21 06:17

まぁこれでしょうね 回答を引き継ぎます
AGLAAGLA

2021/12/21 06:58

ご指摘ありがとうございます。 おっしゃる通り、二回する必要のないconnectをしておりました。 ありがとうございます。
guest

0

ベストアンサー

  • コネクションプールである
  • 持ってこれるコネクションは最大10個

この情報からの推測ですが、

js

1 const client = await pool.connect() 2 3 ... 4 5 finally { 6 client.release() 7 } 8}

この流れでコネクションを作って、リリースして潰してますね。

js

1 pool 2 .connect() 3 .then(() => console.log("接続完了"))

これ is 何?
もう一本コネクション張っちゃってるじゃん。
しかもリリースしてない。


というわけで、本質問の問題点はPromiseとasync/awaitの扱い方をマスターしきれていない事にあります。
Promise決め打ちの.thenメソッドや.catchメソッドはこう書き直しましょう。

js

1async function postgresql_connect(senserid,smell){ 2 const sqltime="SET TIME ZONE 'Asia/Tokyo'" 3 const sql = "INSERT INTO sensor (time,place,conges) VALUES (current_timestamp, $1, $2)" 4 const values = [senserid, smell] 5 // そもそものpool.connectが不要 6 try { 7 // 直でpool.queryを実行すれば良い 8 await pool.query(sqltime) 9 const result = await pool.query(sql, values) 10 console.log(result) 11 } catch (e) { 12 console.error(e) 13 } 14 // そしたらclient.releaseも不要 15}

これで一度様子を見てください。

投稿2021/12/21 06:31

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AGLAAGLA

2021/12/21 06:57

ご丁寧にありがとうございます。 おっしゃる通り、async/awaitの扱い方を勉強すべきと感じました。 こちらの実装で9行以上のデータ挿入を確認することができました。 本当に助かりました。ありがとうございます。
miyabi-sun

2021/12/21 07:26 編集

・await構文はthenメソッドを叩いて第一引数を取り出す必殺技 ・async関数を定義すると、常にPromiseのインスタンスを返すようになり、await構文が有効になる とりあえずこの理解で大丈夫です。 コードからPromise臭をけしていきましょう。頑張って!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問