2008年2月22日 (金)

HQLでINを使用して配列で検索

HQLでINを使用して配列で検索する方法にクセがあったのでまとめです。
…分かりづらい表題で申し訳ない。

※例では架空のHTTPのアクセスログからレコードを検索しています。

◆基本パターン
db_session.createQuery("from AccessLog log where log.url in ('/index.html','/infomation.html')");

ここでURLを変更できるようにしたいと思う…。

String[] url_list = {'/index.html','/infomation.html','/link.html'};
db_session.createQuery("from AccessLog log where log.url in (:urls)").setParameterList("urls",url_list);

ポイント:
① setParameterList メゾットを利用してパラメータを設定する
② :urls の部分を必ず()で囲む

そんなにひねくれてないかもしれないけど、自分は②が分からずに相当苦労した。
知っていればああそうですむ話(^^;

| | コメント (0) | トラックバック (0)

2007年8月20日 (月)

Hibernateアーカイブ(sar)とHot deployでうまくいかなかったこと

雑記メモです以下のようなことがありました。

JBossのHibernateアーカイブ(har)を使用するとデータベースコネクションが
JBoss管理のTransactionに入ります。
同コネクションを使用してINSERTやUTDATEのSQLを直に実行しようとすると
Transactionがでしゃばってきてエラーを返します。

そこでHot deployを利用してHibernateアーカイブを削除してみました。
ところがデータベースコネクションはJBoss管理下のTransactionから抜けることがなく
SQLの更新命令はエラーのままです。

JBossを再起動すると(当然ですが)データベースコネクションはTransactionから抜けて
SQLは受け入れられるようになりました。

総括ではないですが、あるデータベースに対してJDBC(SQL)直制御+Hibernate制御
を行う場合JBossのHibernateアーカイブは不適当なようです。
(SQLでリードのみを行う場合干渉は無い、Write系で問題発生)
ちなみにアーカイブにせずにwarアーカイブ内にHibernateの制御ファイルを
埋め込むパターンではこのような干渉行為は起きませんでした。

*注 この記事の内容は各バージョンでの動作の違いなど細かい検証をしていません。
         ご自分の環境で試すことを推奨します。

| | コメント (0) | トラックバック (0)

2007年8月13日 (月)

hibernate HQL count(*)の値でorderする

ひょっとしたらHibernateネタではなくてSQLネタかもしれない。
*注:例は仮想のテーブルhttpのアクセスログを想定しています。

select ip_address,count(*) as access_count from accress_log group by ip_address order by access_count;

上記のようなSQLを想定して

select log.ipAddress,count(log) as accessCount from AccessLog log group by log.ipAddress order by accessCount;

このようなHQLを書いてもHibernateの処理が通らなかった
どうやら別名でのorder by 句が通らないらしい。
自分はこのパターンしか知らなかったがSQLの辞書にて以下の構文を発見。

select ip_address,count(*) as access_count from accress_log group by ip_address order by 2;

要素を列挙する時の出現順番でorder byを指定することができる。
早速HQLに直してみたところ以下のような文で見事パスした。

select log.ipAddress,count(log) as accessCount from AccessLog log group by log.ipAddress order by 2;

赤字HQL 
青字SQL

| | コメント (0) | トラックバック (0)

2007年7月12日 (木)

HQL(Hibernate)でcount(*)の扱い方

HibernateのHQLでcountを使用した場合オブジェクトへのバインドが
LongになったりIntegerになったりします。
Hibernateのバージョンなどで変ってくるので、それを踏まえてしっかりコーディングしないと
移植などの時に困ったことになります。(自分は困った人です(=_=;))

◆まず悪い例
Integer value = (Integer)db_session.createQuery("select count(log.id) from Log  log").uniqueResult();

◆いい例①
Integer value = new Integer(((Number)db_session.createQuery("select count(log.id) from Log  log").uniqueResult()).intValue());

◆いい例②
Integer value = (Integer)db_session.createSQLQuery("select count(*) as ct from  log").addScalar("ct",new org.hibernate.type.IntegerType()).uniqueResult();

型が予想できないこともあるのでやはり扱い方をあらかじめ通知してあげるのが最適ですね。

| | コメント (0) | トラックバック (0)

2007年1月30日 (火)

Hibernate コレクション の追加/削除処理のコツ

Hibernateでコレクションに登録されているエンティティを
コレクションを保持するエンティティの更新と同時に削除したり追加しようとすると
うまくいかないことがあるので扱い方のメモ。

◆エンティティを更新とコレクションの一部を削除を同時に処理

boss.setName("baramos");
Set zako_set = boss.getZakos();
Object[] zako_array = zako_set.toArray();
for(int i=0;i<zako_array.length;i++){
    Zako zako = (Zako)zako_array[i];
    if(zako.getId.intValue() == 1000){
        db_session.delete(zako);
        zako_set.remove(zako);

    }
}
db_session.update(boss);

ポイントはsession に削除を通知して同時にコレクションからもはずすところ。
怠ると削除されない(bossを更新しなければ削除される)

◆エンティティを更新とコレクションに要素追加を同時に処理

boss.setName("baramos");
Set zako_set = boss.getZakos();
Zako zako = new Zako();
zako.setId(1000);
zako.setName("suraimu A");
zako.setBoss(boss);
zako_set.add(zako);
db_session.update(boss);

コレクションに追加するのがポイント

思うに意図したとおりに動かない場合の原因のほとんどはHibernateが
処理を要求された時ではなくトランザクションの処理時(commit)にそれまでに
要求があった処理を効率的に処理しようとするのが原因だと思う。

セッションに削除が指示されても保持エンティティのコレクションに
存在していると削除すべきかどうかが判断できないということ(?)
コレクションから削除しただけでは削除されないのは他のエンティティの
コレクションに追加されたりコレクションから切り離されて
レコードが存在する可能性があるから(?)

| | コメント (0) | トラックバック (0)

2007年1月18日 (木)

JBoss 4.0.4GAでHibernateのバージョンが上がった件

JBossをアプリケーションサーバーとしていつもどおりセットアップしていたら
Hibernateが何故か動作しない

エラーメッセージは

Exception happened while executing page: tried to access method net.sf.ehcache.CacheManager.

()V from class org.hibernate.cache.EhCacheProvider  

なかんじ

検索した結果

http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3962394

JBossに同胞されているHibernateのバージョンが上がったようす(3.2)です。
それに伴い必要なjarが ehcache-1.1.jar ⇒ ehcache-1.2.3.jar となりました。
Hibernate をDLするともれなくついてきます。

http://ehcache.sourceforge.net/

http://www.hibernate.org/6.html

| | コメント (0) | トラックバック (0)

2006年12月28日 (木)

JBossのHibernateContextが便利そうだ

◆元ネタ◆

http://docs.jboss.org/jbossas/jboss4guide/r2/html/ch13.html#ch13.caveat-har.fig

JBoss provides the                 org.jboss.hibernate.session.HibernateContext             class as the integration piece that does this. The                 getSession method returns a Hibernate session             that is linked to the current JTA transaction. Naturally this             requires that a JTA transaction exist prior to the call. The             following code illustrates the use of getSession.

Session hsession = HibernateContext.getSession("java:/hibernate/CaveatEmptorSessionFactory");

When you get the Hibernate session in this manner, you don't need             close the Hibernate session or manage a hibernate transaction. You             can be sure that all access to the Hibernate session from the             current transaction will see the same state, and you can know that             your Hibernate access will be committed to the database or rolled             back along with the larger JTA transaction.

↑は登録ユーザーのみ閲覧できるスペースなのでひょっとすると
閲覧できないかもしれません。
閲覧できない人はJBOSSをDLして付属ドキュメントの該当ページを参照してください。

Hibernate のアーカイブ(HAR)は多少汚いコードでHibernateを扱っても
安定して動作してくれるので(←根拠無し経験則)愛用していますが
HibernateContextと併用するとSessionを閉じなくてもトランザクションを
管理しなくても
OKなんてステキなドキュメントを発見してしまいました。
Session閉じ忘れてメモリーあふれさせた経験は私だけのものでしょうか??
しかもこの感じですとパフォーマンスも良さげです。

自分はcreateSQLQueryも使うので明示的に適切なタイミングでcommitしないと
結果が変わってきてたいへん困るのですがそのあたりどうなのかな??
いずれレビューしてみます。

なおこのHibernateContextは
${jboss_dir}/server/default/lib/jboss-hibernate.jar にあります。
JBoss4.0.4 で確認しました。
古いバージョンではどこにあるのか良く分かりませんでした(=_=;

| | コメント (0) | トラックバック (0)

2006年8月25日 (金)

Hibernate 3 で ネイティブSQLを使いまわす②Entity編

Hibernate 3 でネイティブなSQLを使いまわすのEntity取り出し編
なんだかSQLの書き方にクセがあったのでまとめたものをメモ

select {log.*} from mail_log_date as {log} where {log}.ad_id = :ad_id and DATE_TRUNC('month',{log}.recode_time) = :times

もしくは

select {log.*} from mail_log_date as log where log.ad_id = :ad_id and DATE_TRUNC('month',log.recode_time) = :times

このような感じ
select {log.*}でマップさせる
where句にプロパティを指定する場合は{log}.***の形式
あるいは{}で囲わない。

http://www.hibernate.org/hib_docs/reference/ja/html/querysql.html
↑には{log.***}の形式が載っていたがうまくいかなかった
仕様書のバージョンが違うのでしょうがない

◆正しく理解したい時はこの頁をよく読む
http://www.hibernate.org/hib_docs/v3/reference/en/html/querysql.html

■関連
http://bellks-tec.cocolog-nifty.com/blog/2006/08/hibernate3_nati_6f44.html


2006/09/29 追記

DATE_TRUNCはPostgreSQLの独自拡張ですね。
はい、MySQL方言使ったりPostgreSQL方言のっけたりばらばらでスイマセン

| | コメント (0) | トラックバック (0)

2006年8月 8日 (火)

Hibernate3 で Native なSQLを使いまわす

Hibernate便利なんだけど、エンティティ(データ本体)だけじゃなくて
データを分析した統計データを使用したいこともDBを使用したシステムなら多々ある。
Hibernateは時間に関係する関数がまったく無いからこのあたりが不便でならない。
という感想はかなりの人が持っていると思うのですがどうでしょうか?

Hibernate3でネイティブなSQLを使いまわす方法(createSQLQueryの用法)を紹介します。
よく紹介されているエンティティを取り出す方法ではなくて
統計データ等(マップされていないデータ)を取り出す方法です。
Hibernate3より前のバージョンでは関数の使い方が違うので要注意。

例1)
SQLQuery query = session.createSQLQuery("select distinct DATE_FORMAT(log.access_time,'%Y-%m-01') month from access_log log order by month desc");
query.addScalar("month",new org.hibernate.type.DateType());
List month_list = query.list();

上の例では架空のアクセスログテーブルに対してアクセスのある月を重複無しで取り出している。
ポイントは2行目addScalarのあたり、マップされていないデータの扱い方を通知する。
ちょっとトリッキーに返すデータの形式をStringからDate型に整形してマップしてみた。
month_listには java.sql.Date が格納されている。

例2)
SQLQuery query = session.createSQLQuery("select distinct DATE_FORMAT(log.access_time,'%Y-%m-01') month,DATE_FORMAT(log.access_time,'%D') day from access_log log order by month desc,day desc");
query.addScalar("month",new org.hibernate.type.DateType());
query.addScalar("day",new org.hibernate.type.IntegerType());
List date_list = query.list();

複数のデータを返すSQLの例
date_listには Object[] が格納されている。
Object[0] が java.sql.Date (例1と同じ値)に対応し Object[1]が日付値の Integerとなる。

注:MySQL使用…方言多様(?)

参考
http://www.powerdee.com/it/hibernate/hibernateQuery.html
http://www.hibernate.org/250.html

| | コメント (0) | トラックバック (1)

2006年4月27日 (木)

『Could not synchronize database state with session』に苦しんだ(改)

アクセスが多い記事なのでまとめて読みやすくしてみました。
オリジナルは
http://bellks-tec.cocolog-nifty.com/blog/2006/02/hibernatecould__0416.html

Hibernateを扱い始めてまもなく難解なエラーが発生

エラーメッセージ:
Could not synchronize database state with session

http://www.hibernate.org/hib_docs/reference/en/html/quickstart.html

上記ページにあるHibernateUtilクラスをあんまり理解せずに流用していたのが主な原因
このクラスの処理はThreadLocalを使用しているのが特徴でThread処理で
一回のみSessionが生成され、あとの呼び出しでは一度生成されたSessionが
使いまわされる仕組みだ。

エラーが出たのは、途中の処理でSessionを閉じていたこと。
その後Sessionを新規で作成しているつもりで

HibernateUtil#currentSession()

を呼び出していたが、ここでは予想と違い閉じられたSessionが
使いまわされて返されていた。
閉じられたSessionのメゾットを呼び出した時点でエラーが発生したということ。

エラーの回避としてはThreadLocalを使用しないようにHIbernateUtilを改造して一件落着(^^)v
パフォーマンス的にはThreadLocalのほうが良いであろうが…

| | コメント (0) | トラックバック (1)

2006年2月 4日 (土)

Hibernateで『Could not synchronize database state with session』に苦しんだ

2006/04/27 この記事はアクセスが多かったので読みやすく書き直しましたコチラもどおぞ
http://bellks-tec.cocolog-nifty.com/blog/2006/04/could_not_synch_ed05.html

HibernateでどうにもDBコネクションの使いまわしがうまくいかない。
DBCPで回収できない接続が残るのかDB接続数がパンクしてしまう。
いろいろと細かい修正を行っているうちになにやらエラーが出てきた

Could not synchronize database state with session

分からん...
更新時にのみでてきたのでどの改造が影響したのかサッパリ
問題解決でCVSにコミットしようと思っていたからCVSにも経過は無し(; ;)

いろいろ検証してゆくと。
何気に更新可能な永続オブジェクトもあることが判明

違いをひたすら探す。
  |
(数時間経過)
  |
全部じゃないがリレーション系が弱い傾向がある…
細かい処理を検証
  |
(数時間経過)
  |
データの取得が入れ子処理になっているところでエラーが起こる。
原因発見!!

http://www.hibernate.org/hib_docs/reference/en/html/quickstart.html

にあるHibernateUtileクラスをよく理解せずに使っていたことが主な原因
今回Tree階層になっているカテゴリーに分類された品物のDBを扱っていた。
Treeの全容を表示する(ルートまで親カテゴリーを表示する)ユーティリティクラスを
作成し使用していたが、この中でHibernateUtile#closesSession()を呼び出していた。

Sessionを開始

商品オブジェクトを取得

商品オブジェクトのカテゴリー全容をユーティリティクラスから取得
(実はここでHibernateUtile#closesSession()が呼び出されSessionがクローズされてしまう)

商品オブジェクトを変更しSession#update
(既に閉じられているSessionのためエラー発生)

Sessionを終了

ということ、設計をひたすら変更し対応(^^;
Threadで使いまわさなくてもいいからSessionFactoryのみ
使いまわすようにしてSessionは毎回作成したほうが安全かもしれない

| | コメント (0) | トラックバック (1)

JBossでHibernateを動かすとき最低限追加設置が必要なJar

『TomcatでHibernateを動かすとき最低限追加設置が必要なJar』
↑↑のJBoss版記事

単純な機能のみを使う場合

ehcache-1.1.jar

2007/01/18 追記 JBoss 4.0.4 GA 以降 ehcache-1.2.3.jar

だけでよい
TreeCacheを使用する場合追加して

jboss-system.jar
jboss-common.jar
jboss-jmx.jar
concurrent-1.3.2.jar

が必要

| | コメント (0) | トラックバック (0)

TomcatでHibernateを動かすとき最低限追加設置が必要なJar

Hibernateの配布ファイル付属のドキュメントにはrequireなjarが
用途別に書いてあるのだが、正直でどれを設置すればいいの?といつも迷う
Tomcatで最低限これを設置したとき動いたという感じのjarのリスト
自分で使用しているぶんには問題ないが使えない機能があるかもしれない
心配な人はしっかりドキュメントを読もう

使用しているHibernateのバージョンは3.0.5

jta.jar
asm.jar
asm-attrs.jar
commons-collections-2.1.1.jar
log4j-1.2.9.jar

#何故か日本語が文字化けるlog4jを設置していればはずしても動いたので後にはずす
(commons-logging-1.0.4.jar)

dom4j-1.6.jar
antlr-2.7.5H3.jar
ehcache-1.1.jar
cglib-2.1.jar

設置した位置は
/share/lib

コッチに設置するほうがスマートかもしれない
/webapps/hoge/WEB-INF/lib

| | コメント (0) | トラックバック (1)

MiddlegenIDEで簡単EJB/Hibernate生成

EJB/HibernateをGUIでDBから作成できる便利なMiddlegen

これをEclipse上から使用できるようにしたのがMiddlegenIDE

Oracle JDeveloperでGUIでEJBが作成出来たのがとても便利で
何とかEclipseでできんのかなぁと思い探し当てました。
なかなか便利で感心しています。

2006-11-08
  以下で紹介しているページはなくなっていました。
  <2006-11-08現在確認できたURL>
  Middlegen http://boss.bekk.no/boss/middlegen/
    ダウンロード http://sourceforge.net/project/showfiles.php?group_id=36044
  またeclipse 3.2に Middlegen IDE 1.3.2をインストールしたところ
    必要なjarはant build時に自動でコピーされるようになっていました

MiddlegenIDE
http://ultimania.org/middlegenide/

セットアップのポイントは必要なjarがたくさんあるということ
別途Middlegenをダウンロード解凍しておきEclipseの
パスに通しておくとよい。
必要なJarは上記URLでjarsとなっている画像を参照のこと

◆使用法
バージョンは古いですが以下のページに良くまとまっています。
http://www.atmarkit.co.jp/fjava/rensai3/eclipseplgn03/eclipseplgn03_3.html

◆少し裏技的Tips

2006-11-08 新しい情報を確認したところデフォルトで作成できるようになっていました

◇EJB(cmp)を生成する

MiddlegenIDEはEJB(cmp)に対応していないことになっているが
MiddlegenをEclipseから起動させるだけのものなので
当然作成することが可能なはずである。
いろいろ試しているうちにMiddlegenとMiddlegenIDEのファイルを比べて
『middlegen-entitybean-plugin-2.1.jar』
がライブラリに足りないことに気が付く。
これをたしてみると普通に作成することに成功した。
足す位置は
[eclipseインストールディレクトリ]\plugins\net.sf.middlegen_2.1.90\lib

◇EJB生成時余計なファイルを作らせない

MiddlegenIDEでEJBを生成するとXdocletが独自の設定で自動的に起動し
必要のないアプリケーションサーバー用の配布ディスクリプトなど
余計なファイルまで作成したりして大変厄介だったりする。
Xdocletの起動スクリプトはVelocityで生成される、
テンプレートは編集が可能なのであらかじめ都合のよいように編集しておく
テンプレートの位置は

[eclipseインストールディレクトリ]\plugins\org.ultimania.middlegenide_1.3.2\resource\template\build-ejb.xml.vm

同フォルダにはhibernate用のテンプレートもあるので必要なら編集してもよいかもしれない。

2006-11-08 追記
<動作確認>

 eclipse 3.2に2006-11-08時点で最新のバージョン1.3.3をインストールしてみたところ
  成城に動作しなかった。
  ひとつ古いバージョン1.3.2をインストールしたところ正常に動作した。
 

| | コメント (0) | トラックバック (0)