ダウンロード
Magazine
開発
アカウント
ダウンロード
Magazine
開発
ログイン
アカウント/パスワードを忘れた
アカウント作成
言語
ヘルプ
言語
ヘルプ
×
ログイン
ログイン名
パスワード
×
アカウント/パスワードを忘れた
日本語の翻訳状況
カテゴリ:
ソフトウェア
人物
PersonalForge
Magazine
Wiki
検索
OSDN
>
ソフトウェアを探す
>
システム
>
TERASOLUNA Framework
>
フォーラム
>
公開討議
>
ストリームの明示的なクローズ処理について
TERASOLUNA Framework
概要
プロジェクト概要
開発ダッシュボード
Webページ
開発メンバー
画像ギャラリー
公開フィード一覧
活動
統計情報
活動履歴
ダウンロード
リリース一覧
統計
ソースコード
コードリポジトリリスト
Subversion
リポジトリ閲覧
チケット
チケット一覧
マイルストーン一覧
チケットの種類一覧
コンポーネント一覧
よく使われるチケット一覧のリスト/RSS
新規チケット登録
文書
Wiki
FrontPageの表示
ページ一覧
最近の更新
文書マネージャ
文書一覧
コミュニケーション
フォーラム
フォーラム一覧
公開討議 (1277)
メーリングリスト
MLの一覧
terasoluna-information
ニュース
フォーラム:
公開討議
(スレッド #35941)
話題(スレッド)一覧に戻る
RSS
ストリームの明示的なクローズ処理について (2014-09-05 10:04 by
anonymous
#74325)
返信
チケットに引用
お世話になります。
「TERASOLUNA Server Framework for Java WEB」2.0.5.0を利用しております。
ibatisでBLOBカラムのデータをjp.terasoluna.fw.orm.ibatis.support.BlobInputStreamTypeHandlerを使って取得した
InputStream型のプロパティがあるBeanクラスで明示的なストリームのクローズ処理は必要でしょうか?
例として、下記のようなコーティングでhogeBeanのfileBlobがInputStream型で
取得したあとにダウンロード用にDownloadInputStreamを生成するような処理です。
--------------------------------------------------------------------------------
HogeBean hogeBean
= queryDAO.executeForObject(SQL_ID, null, HogeBean.class);
try {
// ダウンロード用データ作成
AbstractDownloadObject downloadObject
= new DownloadInputStream(
hogeBean.getFileName(),
hogeBean.getFileBlob());
// ビジネスロジックの戻り値にセット
result.setResultObject(downloadObject);
} finally {
// クローズ処理
IOUtils.closeQuietly(hogeBean.getFileBlob());
}
--------------------------------------------------------------------------------
経験上、クローズ処理を意識して明示的にやってたのは、取得したInputStream型を別オブジェクトを
生成して処理を行うようなときで、上記のように直接Beanの中のストリームをクローズするような
処理はやったことがありません。
イメージ的にはhogeBeanが利用されなくなったらクラスのガベージ処理で
勝手にストリームもクローズされるようなことないのかなぁとか、、
上記のようにクローズを明示的に書かないと
FindBugsが「Streamがfinallyブロック中でクローズされていません」
とか静的チェックで言ってきたりするので気になり投稿させて頂きました。
メッセージ #74325 への返信
×
題名
本文
メッセージ #74325 への返信 > お世話になります。 > > 「TERASOLUNA Server Framework for Java WEB」2.0.5.0を利用しております。 > > ibatisでBLOBカラムのデータをjp.terasoluna.fw.orm.ibatis.support.BlobInputStreamTypeHandlerを使って取得した > InputStream型のプロパティがあるBeanクラスで明示的なストリームのクローズ処理は必要でしょうか? > > 例として、下記のようなコーティングでhogeBeanのfileBlobがInputStream型で > 取得したあとにダウンロード用にDownloadInputStreamを生成するような処理です。 > > -------------------------------------------------------------------------------- > HogeBean hogeBean > = queryDAO.executeForObject(SQL_ID, null, HogeBean.class); > > try { > // ダウンロード用データ作成 > AbstractDownloadObject downloadObject > = new DownloadInputStream( > hogeBean.getFileName(), > hogeBean.getFileBlob()); > > // ビジネスロジックの戻り値にセット > result.setResultObject(downloadObject); > } finally { > // クローズ処理 > IOUtils.closeQuietly(hogeBean.getFileBlob()); > } > -------------------------------------------------------------------------------- > > 経験上、クローズ処理を意識して明示的にやってたのは、取得したInputStream型を別オブジェクトを > 生成して処理を行うようなときで、上記のように直接Beanの中のストリームをクローズするような > 処理はやったことがありません。 > > イメージ的にはhogeBeanが利用されなくなったらクラスのガベージ処理で > 勝手にストリームもクローズされるようなことないのかなぁとか、、 > > 上記のようにクローズを明示的に書かないと > FindBugsが「Streamがfinallyブロック中でクローズされていません」 > とか静的チェックで言ってきたりするので気になり投稿させて頂きました。
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 11:23 by
taromaru
#74326)
返信
チケットに引用
BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。
InputStreamをDownloadInputStreamに与えてから
BLogicResultに入れてreturnした場合、
DownloadBLogicActionまで処理が返ったあとで、
FileDownloadUtil#downloadにDownloadInputStreamが渡り、
レスポンスを返し終わってから、
FileDownloadUtilがDownloadInputStream内のInputStreamをcloseします。
よって、BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。
逆に、closeしてしまうと、FileDownloadUtilが内容を読めずに、ファイルの内容をレスポンスに載せることができないかと思います。
なお、現在のBLogic実装には、気づきにくい問題が潜んでいますので、
付け加えておきます。
まず、JDBCの仕様として、BLobの有効範囲はトランザクション内に限られます。
DownloadInputStreamに与えたInputStreamは、
BLogicの処理が終わってから読み取られるため、
BLogicにAOPでトランザクションをかける一般的なトランザクション境界では、
BLobの有効範囲外(トランザクション外)でBLobの内容を読もうとしてしまいます。
(Oracleでは、どういうわけか、読み取れてしまったりしますが、コネクションをコネクションプールに返してしまった後にDBと通信しているため、
場合によっては別のトランザクションが割り込んだり、ドライバのコネクションがクローズされることもあり得ます。)
対処としては、2つ方法があります。
<対処方法1>
DownloadBLogicActionにAOPでトランザクションをかけ、
DownloadBLogicAction実行時にトランザクションを開始し、
ダウンロード用のBLogicでは、そのトランザクション上で動作するようにする。
(ダウンロード用のBLogicは、トランザクションAOPの対象から外すか、REQUIREDにしておく。)
こちらの方法は、設定で解決するので、楽ですが、1つだけ懸念事項があります。
DownloadBLogicAction(インタフェースなし)にAOPをかけることになり、
AOPを実現するプロキシに、CGLibプロキシが利用されることになります。
CGLibはJava8では動かないという情報があります。
<対処方法2>
BLogicでBLobから取得したInputStreamを読み取り、一時ファイルに書き込み、
DownloadInputStreamには、一時ファイルのFileInputStreamを渡す。
こちらの方法は、一時ファイルの削除タイミングを別途検討する必要があります。
#74325
への返信
メッセージ #74326 への返信
×
題名
本文
メッセージ #74326 への返信 > BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。 > > InputStreamをDownloadInputStreamに与えてから > BLogicResultに入れてreturnした場合、 > DownloadBLogicActionまで処理が返ったあとで、 > FileDownloadUtil#downloadにDownloadInputStreamが渡り、 > レスポンスを返し終わってから、 > FileDownloadUtilがDownloadInputStream内のInputStreamをcloseします。 > > よって、BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。 > 逆に、closeしてしまうと、FileDownloadUtilが内容を読めずに、ファイルの内容をレスポンスに載せることができないかと思います。 > > なお、現在のBLogic実装には、気づきにくい問題が潜んでいますので、 > 付け加えておきます。 > > まず、JDBCの仕様として、BLobの有効範囲はトランザクション内に限られます。 > > DownloadInputStreamに与えたInputStreamは、 > BLogicの処理が終わってから読み取られるため、 > BLogicにAOPでトランザクションをかける一般的なトランザクション境界では、 > BLobの有効範囲外(トランザクション外)でBLobの内容を読もうとしてしまいます。 > (Oracleでは、どういうわけか、読み取れてしまったりしますが、コネクションをコネクションプールに返してしまった後にDBと通信しているため、 > 場合によっては別のトランザクションが割り込んだり、ドライバのコネクションがクローズされることもあり得ます。) > > 対処としては、2つ方法があります。 > > <対処方法1> > DownloadBLogicActionにAOPでトランザクションをかけ、 > DownloadBLogicAction実行時にトランザクションを開始し、 > ダウンロード用のBLogicでは、そのトランザクション上で動作するようにする。 > (ダウンロード用のBLogicは、トランザクションAOPの対象から外すか、REQUIREDにしておく。) > > こちらの方法は、設定で解決するので、楽ですが、1つだけ懸念事項があります。 > DownloadBLogicAction(インタフェースなし)にAOPをかけることになり、 > AOPを実現するプロキシに、CGLibプロキシが利用されることになります。 > CGLibはJava8では動かないという情報があります。 > > <対処方法2> > BLogicでBLobから取得したInputStreamを読み取り、一時ファイルに書き込み、 > DownloadInputStreamには、一時ファイルのFileInputStreamを渡す。 > > こちらの方法は、一時ファイルの削除タイミングを別途検討する必要があります。
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 11:46 by
anonymous
#74327)
返信
チケットに引用
素早い回答ありがとうございます。
「BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。」
とのことで了解しました。
なお、の別問題の話しですが
トランザクション外でBLobを読もうとすることで
実際に発生する事象としては内容が読み取れず正常に処理(この例でいうとダウンロード処理)が出来ないこともあり得るということでしょうか?
それとも、そのBLogic内でなんらかのDB更新処理があった場合にトランザクション外でのエラー発生でロールバック処理が走らないということでしょうか?
対処するにあたり発生事象を的確に認識したく
引き続きの質問となり恐縮ですが、ご回答頂きたく。
#74326
への返信
メッセージ #74327 への返信
×
題名
本文
メッセージ #74327 への返信 > 素早い回答ありがとうございます。 > > 「BLogicで、DownloadInputStreamに与えたInputStreamをcloseする必要はありません。」 > とのことで了解しました。 > > なお、の別問題の話しですが > トランザクション外でBLobを読もうとすることで > 実際に発生する事象としては内容が読み取れず正常に処理(この例でいうとダウンロード処理)が出来ないこともあり得るということでしょうか? > > それとも、そのBLogic内でなんらかのDB更新処理があった場合にトランザクション外でのエラー発生でロールバック処理が走らないということでしょうか? > > 対処するにあたり発生事象を的確に認識したく > 引き続きの質問となり恐縮ですが、ご回答頂きたく。
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 12:26 by
taromaru
#74328)
返信
チケットに引用
> トランザクション外でBLobを読もうとすることで
> 実際に発生する事象としては内容が読み取れず正常に処理(この例でいうとダウンロード処理)が出来ないこともあり得るということでしょうか?
十分あり得ます。
まず、トランザクション外では、
コネクションはコネクションプールに返し終わっている状態です。
そのコネクションに割り当てられた物理コネクションが閉じられると、
DBとの通信が切れている状態になるので、データを取得することは不可能になります。
# ただし、ドライバのConnectionのcloseメソッドを実行したときに、
# 直ちに通信を切断するかは、JDBCドライバの実装によります。
物理コネクションが閉じられていない場合、経験上、データは取得できるのですが、
そのデータが正しく取得できる保証はありません。
(仕様外の挙動なので、仮に今大丈夫で、
DBにパッチを当てて動作に影響がでても、
有効範囲外で使用しているのがそもそもの誤りなので、
文句は言えないと思ってください。)
> それとも、そのBLogic内でなんらかのDB更新処理があった場合にトランザクション外でのエラー発生でロールバック処理が走らないということでしょうか?
トランザクション外ではロールバックできません。
BLogicにトランザクション境界があれば、
BLogicが終わった時点(ダウンロード前)で、すでにコミットされています。
(BLogic内から例外が上がった場合は、ロールバックされます。)
#74327
への返信
メッセージ #74328 への返信
×
題名
本文
メッセージ #74328 への返信 > > トランザクション外でBLobを読もうとすることで > > 実際に発生する事象としては内容が読み取れず正常に処理(この例でいうとダウンロード処理)が出来ないこともあり得るということでしょうか? > 十分あり得ます。 > まず、トランザクション外では、 > コネクションはコネクションプールに返し終わっている状態です。 > そのコネクションに割り当てられた物理コネクションが閉じられると、 > DBとの通信が切れている状態になるので、データを取得することは不可能になります。 > # ただし、ドライバのConnectionのcloseメソッドを実行したときに、 > # 直ちに通信を切断するかは、JDBCドライバの実装によります。 > 物理コネクションが閉じられていない場合、経験上、データは取得できるのですが、 > そのデータが正しく取得できる保証はありません。 > (仕様外の挙動なので、仮に今大丈夫で、 > DBにパッチを当てて動作に影響がでても、 > 有効範囲外で使用しているのがそもそもの誤りなので、 > 文句は言えないと思ってください。) > > > それとも、そのBLogic内でなんらかのDB更新処理があった場合にトランザクション外でのエラー発生でロールバック処理が走らないということでしょうか? > トランザクション外ではロールバックできません。 > BLogicにトランザクション境界があれば、 > BLogicが終わった時点(ダウンロード前)で、すでにコミットされています。 > (BLogic内から例外が上がった場合は、ロールバックされます。)
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 13:36 by
anonymous
#74329)
返信
チケットに引用
taromaru様
回答ありがとうございます。
最初に教えて頂いた<対処方法2>で一時ファイルを作成する形で検討します。
(一時ファイルの削除タイミングは別途検討します)
ちなみに「DownloadInputStreamに一時ファイルのFileInputStreamを渡す」とのことでしたが
そもそもダウンロード用のオブジェクトにDownloadInputStreamではなく、DownloadFileを使って
IOUtils.copyなどでFileOutputStreamから書き込んだ一時ファイルを渡せば
FileInputStreamは使用しなくて良いと思うのですが
どちらのオブジェクトをダウンロード用で使うかでBLogic以降の処理で
何かメリデメや他の懸念点などはありますか?
#74328
への返信
メッセージ #74329 への返信
×
題名
本文
メッセージ #74329 への返信 > taromaru様 > 回答ありがとうございます。 > > 最初に教えて頂いた<対処方法2>で一時ファイルを作成する形で検討します。 > (一時ファイルの削除タイミングは別途検討します) > > ちなみに「DownloadInputStreamに一時ファイルのFileInputStreamを渡す」とのことでしたが > そもそもダウンロード用のオブジェクトにDownloadInputStreamではなく、DownloadFileを使って > IOUtils.copyなどでFileOutputStreamから書き込んだ一時ファイルを渡せば > FileInputStreamは使用しなくて良いと思うのですが > > どちらのオブジェクトをダウンロード用で使うかでBLogic以降の処理で > 何かメリデメや他の懸念点などはありますか?
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 16:49 by
taromaru
#74331)
返信
チケットに引用
> どちらのオブジェクトをダウンロード用で使うかでBLogic以降の処理で
> 何かメリデメや他の懸念点などはありますか?
DownloadFileの方が、レスポンスにファイルサイズ(正のint)が入るため
正のintで表現可能なサイズであれば、
ブラウザでプログレスバーを表示できるはずです。
2GB以上の場合は、ファイルサイズ[byte]が正のintに収まらないため、
レスポンスにファイルサイズが入りません。
(DownloadInputStreamの場合は、常に、レスポンスにファイルサイズが入りません。)
そうなると、ブラウザはダウンロードするファイルのサイズを
ダウンロード完了時まで知ることができないため、
プログレスバーを表示することはできません。
よって、ファイルサイズは2GBはないが、
そこそこダウンロードに時間がかかるサイズである
(プログレスバーを確認したくなるサイズである)
という場合には、DownloadFileの方がお奨めといえます。
DownloadFile使用時に気をつけることは、
コンストラクタで与えるファイル名(最初に貼り付けられたBLogicではDBから取得)が
nullまたは空文字だった場合、ファイルシステム上のファイル名が、
ダウンロードファイル名として利用される点です。
APサーバで使用している一時ファイルのファイル名がクライアントで分かり、
OSやその他ソフトウェアの脆弱性との合わせ技で、
他者のダウンロードファイルの詐取の手助けになってしまう可能性があります。
そのため、
DBから取得したファイル名がnullや空文字列だった時には
固定のファイル名を使用するよう、
BLogicで実装することをお奨めします。
その他の懸念として、
今回はBLobから取得したデータなので無いとは思いますが、
ダウンロードするファイルのサイズが4GBを超える場合は、
DownloadFileを使用すると、
ファイルサイズをintにする際に、ファイルサイズより小さな正のintになってしまうことで、
レスポンスに誤ったファイルサイズが与えられてしまい、
ファイルの一部しかダウンロードできない事象が発生する可能性があります。
このような、特大のファイルをサポートする場合は、
DownloadInputStreamを選択することになります。
#74329
への返信
メッセージ #74331 への返信
×
題名
本文
メッセージ #74331 への返信 > > どちらのオブジェクトをダウンロード用で使うかでBLogic以降の処理で > > 何かメリデメや他の懸念点などはありますか? > DownloadFileの方が、レスポンスにファイルサイズ(正のint)が入るため > 正のintで表現可能なサイズであれば、 > ブラウザでプログレスバーを表示できるはずです。 > 2GB以上の場合は、ファイルサイズ[byte]が正のintに収まらないため、 > レスポンスにファイルサイズが入りません。 > (DownloadInputStreamの場合は、常に、レスポンスにファイルサイズが入りません。) > そうなると、ブラウザはダウンロードするファイルのサイズを > ダウンロード完了時まで知ることができないため、 > プログレスバーを表示することはできません。 > > よって、ファイルサイズは2GBはないが、 > そこそこダウンロードに時間がかかるサイズである > (プログレスバーを確認したくなるサイズである) > という場合には、DownloadFileの方がお奨めといえます。 > > DownloadFile使用時に気をつけることは、 > コンストラクタで与えるファイル名(最初に貼り付けられたBLogicではDBから取得)が > nullまたは空文字だった場合、ファイルシステム上のファイル名が、 > ダウンロードファイル名として利用される点です。 > APサーバで使用している一時ファイルのファイル名がクライアントで分かり、 > OSやその他ソフトウェアの脆弱性との合わせ技で、 > 他者のダウンロードファイルの詐取の手助けになってしまう可能性があります。 > そのため、 > DBから取得したファイル名がnullや空文字列だった時には > 固定のファイル名を使用するよう、 > BLogicで実装することをお奨めします。 > > その他の懸念として、 > 今回はBLobから取得したデータなので無いとは思いますが、 > ダウンロードするファイルのサイズが4GBを超える場合は、 > DownloadFileを使用すると、 > ファイルサイズをintにする際に、ファイルサイズより小さな正のintになってしまうことで、 > レスポンスに誤ったファイルサイズが与えられてしまい、 > ファイルの一部しかダウンロードできない事象が発生する可能性があります。 > このような、特大のファイルをサポートする場合は、 > DownloadInputStreamを選択することになります。
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル
Re: ストリームの明示的なクローズ処理について (2014-09-05 20:34 by
anonymous
#74333)
返信
チケットに引用
taromaru様
様々な有益な情報ありがとうございます。
教えて頂いた情報を元に検討を進めます。
#74331
への返信
メッセージ #74333 への返信
×
題名
本文
メッセージ #74333 への返信 > taromaru様 > > 様々な有益な情報ありがとうございます。 > 教えて頂いた情報を元に検討を進めます。
Wiki文法は使えません
ログインしていません。投稿を区別するために投稿者のニックネームをつけてください(ニックネームの一意性は保証されません。全く別の人も同じ名前を利用することが可能ですので本人であることの特定には利用できません。本人であることを保証したい場合にはログインして投稿を行なってください)。
ログインする
ニックネーム
プレビュー
投稿
キャンセル