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

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

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

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

2回答

4975閲覧

updateBigDecimalでこの ResultSet はクローズされています(Kotlin×PostgreSQL)

picohead

総合スコア8

PostgreSQL

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2020/04/29 07:36

編集2020/04/29 07:39

前提・実現したいこと

ResultSetでupdateBigDecimalしたい。

しかし、オープン状態のはずなのに下記のエラーが出てしまう。
"org.postgresql.util.PSQLException: この ResultSet はクローズされています。"

発生している問題・エラーメッセージ

org.postgresql.util.PSQLException: この ResultSet はクローズされています。 at org.postgresql.jdbc.PgResultSet.checkClosed(PgResultSet.java:2741) at org.postgresql.jdbc.PgResultSet.findColumn(PgResultSet.java:2588) at org.postgresql.jdbc.PgResultSet.updateBigDecimal(PgResultSet.java:1467) 秘匿

該当のソースコード

kotlin

1秘匿 2try{ 3 秘匿 4 rset = stmt!!.executeQuery(秘匿); 5 println(rset!!.isClosed());//false 6 while(rset!!.next()){ 7 秘匿 8 println(rset!!.isClosed());//false 9 rset!!.updateBigDecimal(秘匿));//PSQLExceptionの発生行 10 rset!!.updateRow(); 11 println(rset!!.isClosed()); 12 } 13 conn!!.commit(); 14 秘匿 15 } 16}catch(e: Exception){ 17 println(rset!!.isClosed());//false 18 e.printStackTrace(); 19}finally{ 20 println(rset!!.isClosed());//false 21} 22秘匿

試したこと

各所でrset!!.isClosed()を出力してみましたが、すべてfalseで、オープンの状態でした。

私が思いつくのは下記のどちらかです。
isClosedではクローズ状態を判定できない。
または
(ないとは思いますが)表示されるエラーメッセージがおかしい。

補足情報(FW/ツールのバージョンなど)

・kotlincは1.3.60
・PostgreSQL12
・postgresql-42.2.5.jar

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

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

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

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

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

picohead

2020/05/03 06:10

頂いたリンクは残念ながら「Entry is not found」でした。 使い終わったらnullを代入するため、null許容型にしています。 Kotlinのガベージコレクションがよくわからず、これが正しいのかわかりません。 また、1つのSQL文ごとに各関数でDBの接続・切断を行っていたのですが、全体の処理時間の99%以上がDBの接続だったため、グローバル変数にして使いまわしたところ、処理時間は圧倒的に改善したのですが、!!演算子がないとコンパイルが通らなくなってしましました。 DBは占有可能な仕様のためOKとしましたが、この対応で良いのか、私自身、疑問に思っていました。 この場合、普通はどうするのが正解なのでしょうか。
shiketa

2020/05/03 07:12 編集

> 頂いたリンクは残念ながら「Entry is not found」でした。 あら。`Kotlin入門までの助走読本`でお探しください。 > 使い終わったらnullを代入するため、null許容型にしています。 Javaのtry-with-resouceぽいことができる use() 関数を使うのも手かと。 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/use.html `conn.createStatement().use{stmt ->stmt.executeQuery(秘匿).use{rset -> ...}}` > Kotlinのガベージコレクションがよくわからず、これが正しいのかわかりません。 結局はJVM上で動くので、べつにKotlinだからどうこうはないのではないかと。 > ...この場合、普通はどうするのが正解なのでしょうか。 接続プールを使う、かな。 https://www.postgresql.jp/document/7.4/html/jdbc-datasource.html
guest

回答2

0

ベストアンサー

いちおてきとうな内容でデータを更新してみました。再現は、できませんでした。

kotlin

1import java.sql.DriverManager 2import java.sql.ResultSet 3import java.time.LocalDateTime 4 5object xxHoge { 6 @JvmStatic 7 fun main(args: Array<String>) { 8 DriverManager.getConnection("jdbc:postgresql://localhost:5432/test", "秘匿", "秘匿").use { conn -> 9 println(conn::class.java) 10 println(conn.metaData.driverName) 11 println(conn.metaData.driverVersion) 12 println(conn.metaData.jdbcMajorVersion) 13 println(conn.metaData.jdbcMinorVersion) 14 conn.createStatement().use { stmt -> 15 stmt.execute("drop table if exists test") 16 stmt.execute("create table test (id text primary key, name text, num bigint)") 17 stmt.execute("insert into test (id, name, num) values('01', 'aa', 1)") 18 stmt.execute("insert into test (id, name, num) values('02', 'bb', 2)") 19 stmt.execute("insert into test (id, name, num) values('03', 'cc', 3)") 20 21 println("--") 22 stmt.executeQuery("select id, name, num from test").use { rs -> 23 val meta = rs.metaData 24 while (rs.next()) { 25 val row = 26 (1..meta.columnCount) 27 .map { index -> meta.getColumnName(index) to rs.getString(index) } 28 .toMap() 29 println("row : ${row}") 30 } 31 } 32 } 33 34 conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE).use { stmt -> 35 println("-- update") 36 stmt.executeQuery("select id, name, num from test").use { rs -> 37 val meta = rs.metaData 38 while (rs.next()) { 39 rs.updateString(2, LocalDateTime.now().toString()) 40 rs.updateBigDecimal(3, System.nanoTime().toBigDecimal()) 41 rs.updateRow() 42 } 43 } 44 } 45 46 conn.createStatement().use { stmt -> 47 println("--") 48 stmt.executeQuery("select id, name, num from test").use { rs -> 49 val meta = rs.metaData 50 while (rs.next()) { 51 val row = 52 (1..meta.columnCount) 53 .map { index -> 54 meta.getColumnName(index) to rs.getString(index) 55 } 56 .toMap() 57 println("updated row : ${row}") 58 } 59 } 60 } 61 } 62 } 63} 64 65//class org.postgresql.jdbc.PgConnection 66//PostgreSQL JDBC Driver 67//42.2.12 68//4 69//2 70//-- 71//row : {id=01, name=aa, num=1} 72//row : {id=02, name=bb, num=2} 73//row : {id=03, name=cc, num=3} 74//-- update 75//-- 76//updated row : {id=01, name=2020-05-03T20:38:51.912669, num=24028744079186} 77//updated row : {id=02, name=2020-05-03T20:38:51.949183, num=24028755991783} 78//updated row : {id=03, name=2020-05-03T20:38:51.951468, num=24028758275722}

useを使用するにはどうしたら良いでしょうか。

追記。

IntelliJでGradleの新規プロジェクトをJavaとKotlin/JVMを選択して生成したときのbuild.gradleを添付しておきます。なお、JDBCドライバ(PostgreSQ)Lの依存だけは手動で追加しました。以外は生成したままです。おそらくkotlin-stdlibの追加が必要なのでしょう。

plugins { id 'java' id 'org.jetbrains.kotlin.jvm' version '1.3.72' } group 'org.example' version '1.0-SNAPSHOT' repositories { mavenCentral() } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testCompile group: 'junit', name: 'junit', version: '4.12' runtime group: 'org.postgresql', name: 'postgresql', version: '42.2.12' } compileKotlin { kotlinOptions.jvmTarget = "1.8" } compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }

投稿2020/05/03 11:41

編集2020/05/04 12:08
shiketa

総合スコア3971

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

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

picohead

2020/05/04 05:57

ソースありがとうございます。 書き方は異なりますが、アドバイス通りResultSetの定数を渡しつつcreateStatementしてexecuteQueryしてupdate~するのは一緒なんですね。。。 use使ってないことなどに原因があるのかと思い、ソースを試してみたところ、コンパイルエラーが出て、 import java.sql.Connection; import java.sql.Statement; を追記して型を明示したところ、.useの全行で下記のコンパイルエラーとなりました。 ============ UpdTest.kt:11:113: error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: @InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> ???): ??? defined in kotlin.io DriverManager.getConnection(秘匿).use { conn: Connection -> ============ useを使用するにはどうしたら良いでしょうか。
picohead

2020/05/06 06:04

申し訳ございません。 updateBigDecimal(秘匿)の秘匿部分で、別の自作関数を呼び出していました。 そちらで共有しているグローバル変数のconnをcommitしており、その際にクローズされていたようで、別で接続したら解決しました。 なお、kotlin-stdlibを追加しても同じエラーでした。 エラーメッセージにもdefined in kotlin.ioとありますし、下記と類似の現象なのかと思いました。 https://qiita.com/m-sugawara/items/f462136bc53dc709ee3a こちらは本題ではありませんので、空いた時に調査を続けてみようかなと思います。 長い間、お付き合い頂きありがとうございました!!
guest

0

肝心の部分が提示されていないので、あくまでも推測です。「スクロールまたは更新、あるいはその両方が可能なResultSetオブジェクトを生成」していないのでは?

see: https://docs.oracle.com/javase/jp/8/docs/api/java/sql/ResultSet.html

スクロールまたは更新、あるいはその両方が可能なResultSetオブジェクトを生成できます。conが有効なConnectionオブジェクトである次のコード・フラグメントは、スクロール可能でほかで行われた更新を反映しない結果セット、および更新可能な結果セットの作成方法を示しています。

java

1 Statement stmt = con.createStatement( 2 ResultSet.TYPE_SCROLL_INSENSITIVE, 3 ResultSet.CONCUR_UPDATABLE); 4 ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2"); 5 // rs will be scrollable, will not show changes made by others, 6 // and will be updatable

投稿2020/04/29 13:11

編集2020/04/29 13:34
shiketa

総合スコア3971

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

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

picohead

2020/05/03 05:57

ご回答ありがとうございます。 試してみましたが、エラーの内容は変わりませんでした。 しかし、オープンになった時、「更新可能でない」的なエラーが想定されるため、おかげさまで未来のエラーを先に潰せたのかなと思います。
shiketa

2020/05/03 07:23 編集

コメント取り下げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問