Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

NetBeans 8.2のSQL Profiler機能

ふとTwitter眺めていたら以下情報が流れてきました。

NetBeans SQL Profilerとな!

せっかくなので、私もnightly buildを落として実際に触ってみました。
ちなみに次のNetBeans、Docker対応なんかもあるっぽいです。以下アイコンがありました。NetBeans 8.2で入る予定の機能とかは最後簡単に触れます。

f:id:kikutaro777:20160504172816j:plain

NetBeans IDE Build 201605020002インストール

Nightly Build版は以下から取得しました。

Index of /dev/nightly/

最初「NetBeans IDE Build 201605030002」を落としたのですが、手元のWindows 8.1だと以下エラーに(^^;

f:id:kikutaro777:20160504171618j:plain

何回かDLしたけど同じだったため、1つ古い「NetBeans IDE Build 201605020002」をインストールしました。

SQL Profiler

デフォで入ってるJava DBのサンプルDBと、NetBeansのコード自動生成で簡単なDB CRUDのJava EEを作成して試しました。

SQL Profilerの設定

スクショ取るのが手間だったので…以下gifアニメにて。使い方はNetBeansが持ってる通常のプロファイラ機能とほとんど一緒です。SQL Profilerを選ぶだけ。

f:id:kikutaro777:20160504165318g:plain

DBデータの一覧表示

Webアプリ側でDBの一覧表示をすると、実行されたSQLがガガガーっと表示されました。ほー。

f:id:kikutaro777:20160504170115g:plain

SQL実行の実行時間や呼出し回数などが表示されています。

f:id:kikutaro777:20160504172259j:plain

DBデータの更新

以下のキャプチャはinsertだけですが、当然deleteなども同じように表示されました。

f:id:kikutaro777:20160504165614g:plain

実行されたクエリも「View SQL Query」を選ぶと

f:id:kikutaro777:20160504172545j:plain

以下、確認できます。

f:id:kikutaro777:20160504172552j:plain

NetBeansロードマップ

NetBeansのロードマップは以下ページで確認できます。

netbeans.org

次の8.2は今年2016年の8月リリースを目指して動いてるようです。JDK9への対応具合などは多分Java Day Tokyo 2016JJUG CCC 2016 Springなどで何らか少しは出てくるのではないかと。

8.2では以下の機能が挙げられています。

JShellやES6対応辺りは注目度高そう。また、冒頭キャプチャだけ載せたDockerも入ってます。
そして、Oracle JET…お、おう。

  • ECMAScript 6 support
  • NodeJS enhancements and updates
  • Oracle JET support enhancements
  • PHP7 support
  • JavaShell support (JDK REPL)
  • Docker Support
  • Editor Multicarets
  • Pinnable Watches
  • SQL profiling
  • CND updates
  • more bug fixing

Editor MulticaretsとかPinnable Watchesは何だろう…(^^;全然わからないのでどこかで調べてみたい。

JPAのCDI Entity Listenersを試してみた

久しぶりにJPAネタです。

Java EE 7のJPA 2.1からEntity ListenerでCDIが利用できるようになりました。

EclipseLinkの例だと@EJBで書かれてます。
EclipseLink/Release/2.5/JPA21 - Eclipsepedia

この例だと、うーんロガーをわざわざEJBでかぁ…(^^;という感じが個人的にしたので、前にきしださんが書いていたプロデューサー使う方法でやってみました。d.hatena.ne.jp

LoggerProducerはそのまんまお借りして

@Named
@Dependent
public class LoggerPoducer {

    @Produces
    public Logger getLogger(InjectionPoint ip){
        return Logger.getLogger(ip.getMember().getDeclaringClass().getName());
    }
}

EclipseLinkの例にあったLoggerEntityLisetenerの@EJBを@Injectへ

public class LoggerEntityListener {
   @Inject //ProducerでInjectされる
   private Logger logger;
    
   @PrePersist
   public void prePersist(Object object) {
       logger.info("prePersist");
   }
   
   @PostPersist
   public void postPersist(Object object){
       logger.info("postPersist");
   }
   
   @PreDestroy
   public void preDestroy(){
       logger.info("preDestroy");
   }
   
   @PostConstruct
   public void postConstruct(){
       logger.info("postConstruct");
   }
}

そして、対象のEntityクラスに@EntityListenersでLoggerEntityListenerを指定しました。

@Entity
@EntityListeners({LoggerEntityListener.class})

EclipseLinkは2.5.2、APサーバはGlassFish 4.1で試したのですが…なぜかloggerがnullで上手くインジェクトされませんでした。

色々調べていたら以下に辿り着き

github.com

上記に以下リンクがありますが、GF4.1の問題っぽい?現象としてはこれと全く同じでした。
[GLASSFISH-21195] CDI Injection in Entity Listener - NullPointerException - Java.net JIRA

さらに読むとEclipseLink2.5.2の問題じゃないかみたいな。
Bug 438105 – Logic bug in EntityListenerInjectionManagerImpl

で、最終的には、最新のPayaraにはEclipseLink2.6が入って、それで動くよとのこと。

ということで、初めてPayaraをダウンロードしました。中はホント完全にGlassFishなんですね(^^;
Pre-Release Builds

利用したのは「Payara-web 4.1.153 (Web Profile)」です。

そして実行すると…動きました!

f:id:kikutaro777:20150618225652j:plain

GlassFishをPayaraに変えるのは全く手間がなさそうです。普通に動くし、今回のようにPayaraのほうが対応が早いケースがあるのを知ると、ちょっと真面目にPayara追っていかないとなーと。

前から既に追っているはすぬまさんのブログで勉強していかねば!

www.coppermine.jp

既にめっちゃPayaraについて書かれている(*´Д`)さすがすぎる

はすぬまさんのブログで「Payara」のタグがついている記事の検索結果
Programming Studio - 検索結果

CDI Entity Listenersについての日本語参考情報は以下。

etc9.hatenablog.com

qiita.com

jta-data-source名に__pmが付けられてエラーとなる

これ、ハマってる方がいるのかわからないのですが、自分は結構ハマったのでメモ。

手元の環境は

Windows 8 Pro(64bit)
JDK 7u67
NetBeans 8.0.1
GlassFish 4.1

で、Java DB(Derby)のテーブルからNetBeansの自動生成機能でエンティティ・クラス作ったりしたアプリをデプロイしたとき

重大: Exception while preparing the app : Invalid resource : MemoJNDI__pm
com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: Invalid resource : MemoJNDI__pm
at org.glassfish.jdbcruntime.service.JdbcDataSource.validateResource(JdbcDataSource.java:81)
at org.glassfish.jdbcruntime.service.JdbcDataSource.setResourceInfo(JdbcDataSource.java:62)
at org.glassfish.jdbcruntime.JdbcRuntimeExtension.lookupDataSourceInDAS(JdbcRuntimeExtension.java:136)
…略

みたいなエラーでこけてしまう。うーん、今まであまりなったことなかったのに…と。

自動生成されたpersistence.xmlのjta-data-sourceは

<persistence-unit name="sample.javaee_MemoApp_war_1.0PU" transaction-type="JTA">
    <jta-data-source>MemoJNDI</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
</persistence-unit>

となっていて「__pm」なんてつけてないんだけど…??みたいな。

ググると海外情報では同じエラーの人が多々いて、回答みてやってみたりもしたけど、ダメでした。


java - Glassfish can not find JNDI DataSource while deploying - Stack Overflow


java - JNDI resource name appended with _pm . Deployment fails . - Stack Overflow


java - Glassfish Server Error when deploy .war: Error occurred during deployment: Exception while preparing the app : Invalid resource - Stack Overflow

http://www.nagazuka.nl/2014/03/invalid-resource-with-netbeans-8_27.html

というか、GlassFish3.1.2.2とかNetBeans7.3でもなってるっぽい。自分はなったことないのだが。。。

で、ドメインを作り直すと、普通に動くようになりました。
前に@megascusさんが以下ブログでパスワードの所で注意、とあって、一番下にドメイン作り直し、というをやってみた感じ。


#JJUG_CCC Java EE 7 HoL補足 - 水まんじゅう

NetBeansのサーバ追加で新しくGlassFish4.1を食わせなおしただけですが。

f:id:kikutaro777:20140915165534j:plain

デフォルトで作られるドメインが駄目なのかなぁ。domain.xmlとか細かく見比べてみないと。

NetBeansで自動生成されるglassfish-resources.xmlでJDBCのconnection-poolやresourceを定義するのではなく、GlassFishの管理コンソールで手動作成すればいけるとも書いてありましたが、まだ試してないです。

Querydslを触ってみる

今のJava EE開発では、JPQLを書く際

  • 動的クエリ(Dynamic Query)
  • 名前付きクエリ(Named Query)

を使うようにしていて、本来、型のことなど考えるとCriteriaで書くべきだなんだろうな…と思いつつ、可読性や簡易性を優先して上記選択にしています。

ただ、どうしても動的クエリはStringBuilderなどでクエリをダラダラと連結することになって、わりとイケてないらしい…ですね。

ということで、前に@megascusさんがブログで紹介されていたQuerydslを思い出し、これから少し触っていこうかなと。

QuerydslでJPAが思ったよりも捗る

上記ブログ記事の中にあるサンプルコードや、公式サイトのチュートリアルに接頭辞「Q」が付いたEntityクラスみたいなものが出てくるので、なんなんだろあれ?と思ってたのですが、定義したEntityクラスをベースにQuerydslが(というか実際にはapt(Annotation Processing Tool))が自動生成するクラスなんですね。

ってかapt初めて知りました(^^;
ググるとき気を付けないとLinuxのaptが出てきそう…(^^;

……

そんなこんな調べつつ、QuerydlsのドキュメントからQuerying JPAのチュートリアルを参考に触ってみました。

Mavenによる依存性定義

pom.xmlは以下としました。

<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>3.3.2</version>
</dependency>

公式のみるとslf4jも入れたほうが良いようですね(今回は省略しましたが一応動いてます)。

今日時点で最新の3.3.2は2014年3月24日にリリースされたものなので、わりと最近でもメンテされてるライブラリのようです。

3系の最新定義するなら上記pom.xmlのversionタグを

<version>[3,)</version>

のように指定してもいいかもしれません。

maven-apt-pluginの定義

コード自動生成のためにpom.xmlのbuildタグ内のpluginsで以下定義を追加します。

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>maven-apt-plugin</artifactId>
    <version>1.0</version>
    <executions>
      <execution>
        <goals>
          <goal>process</goal>
        </goals>
        <configuration>
          <outputDirectory>target/generated-sources/java</outputDirectory>
          <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
        </configuration>
      </execution>
    </executions>
  </plugin>

今回Java EE 7、GlassFish 4.0でサンプルを作りましたが、Entityの生成などはJava EE 6と同様にNetBeans任せで、データベースから自動的に作りました。

そしてビルドすると

f:id:kikutaro777:20140421223509j:plain

EntityのActress.java(NetBeansから自動生成したEntity)に対してQActress.java(Querydls&aptで自動生成)が出来ています。

テーブルサンプル

Actressテーブルは以下定義しました。

ID 名前 年齢
1 堀北真希 25
2 橋本環奈 15
3 橋本愛 18
4 能年玲奈 20
5 有村架純 21

サンプルコード

堀北さんをピンポイントで拾ってみます。EJBで

public Actress getHorikita(){
    QActress actress = QActress.actress;
    JPQLQuery query = new JPAQuery(em, EclipseLinkTemplates.DEFAULT);
    return query.
            from(actress).
            where(actress.name.eq("堀北真希")).
            uniqueResult(actress);
}
[ id:1, name:堀北真希, age:25 ]

橋本さんをlike文で検索して、名前でソート昇順に。

public List<Actress> getHashimoto(){
    QActress actress = QActress.actress;
    JPQLQuery query = new JPAQuery(em, EclipseLinkTemplates.DEFAULT);
    return query.
            from(actress).
            where(actress.name.like("橋本%")).
            orderBy(actress.name.asc()).
            list(actress);
}
[[ id:3, name:橋本愛, age:18 ], [ id:2, name:橋本環奈, age:15 ]]

成人した女優さん達は

public List<Actress> getAdult(){
    QActress actress = QActress.actress;
    JPQLQuery query = new JPAQuery(em, EclipseLinkTemplates.DEFAULT);
    return query.
            from(actress).
            where(actress.age.goe(20)).
            list(actress);
}
[[ id:1, name:堀北真希, age:25 ], [ id:4, name:能年玲奈, age:20 ], [ id:5, name:有村架純, age:21 ]]

goeは「>=」でgtが「>」。逆はloe、lt。

テーブルが超簡易なのであれですが、良い感じ!
もう少し複雑なクエリ組んでみよう。

これ採用してもいいんじゃないかなー。開発元はmysemaというフィンランドの企業がやっているらしい。

コードはGitHubで管理されてて、わりと活発そうです。
https://github.com/mysema/querydsl

発行されるJPQLをどうやって確認できるのかな?と思ったのですが、普通にNetBeansでも表示されてるっぽい。

f:id:kikutaro777:20140421233638j:plain

Java EEを利用したオフラインWebシステム構築にChallenge! ~その2~

昨日の続きです。

f:id:kikutaro777:20140207202741p:plain

Java EEを利用したオフラインWebシステム構築にChallenge! ~その1~

上記のような仕組みでJava EEで構築したシステムをオフライン化してるのですが、昨日も書いたようにオンラインとオフラインで異なるデータベースを利用しています(^^;

ここが本当に気になって気になって、誰でも同じ心配をすると思うのですが

f:id:kikutaro777:20140208184410p:plain

という疑問が。

実際DDLとかの記述では違いもあって、自動採番で1ずつインクリメントするカラムなど

MS SQLだと IDENTITY(1,1)

ですが

Derby だと IDENTITY(START WITH 1,INCREMENT BY 1)

だったり(^^;

元々存在しているオンラインのシステムがどんなテーブル定義をしているか、それらをオフライン側のデータベースで使えるのか、はベタにコツコツ調査するしかないかなと。

今回特に注意してたのは

  • ストアドやトリガー、その他ベンダ依存の機能利用があるかないか
  • どんなデータ型を利用しているか、お互いで互換がありそうかどうか

辺りでした。幸い今回オフライン対象となったシステムでは前者で該当するものがないシンプルな作りだったので、後者をメインに調査。

MS SQL ServerもApache Derbyも各々ドキュメントは豊富なのでありがたいですが、どう調べて検証すればいいのか…よくわからず、以下のように行いました。

とりあえずMicrosoft SQL Serverを利用する際、JDBCドライバを介するので、そこのドキュメントを確認。
http://technet.microsoft.com/ja-jp/library/ms378599.aspx

基本型のマッピング表が以下のようにあります。
http://technet.microsoft.com/ja-jp/library/ms378878.aspx

まずはここから対象システムで利用しているSQLの型とJDBCのマッピングを抜粋しました。

SQL Server型 JDBC型
bit BIT
int INTEGER
nvarchar VARCHAR
NVARCHAR
datetime TIMESTAMP

などなど。他にも色々あるのですが、ここでは一部抜粋でこんな感じに。

Derbyのドキュメントでもデータ型に関する場所があります。
Data typesという章の部分。
http://db.apache.org/derby/docs/10.10/ref/
※利用バージョンごとにちゃんとドキュメントは分かれています

ここでデータ型をみてみると、JDBCでの型が確認できます。例えばINTEGERの部分をみると以下のような感じです。

f:id:kikutaro777:20140208192731j:plain

で、ここからJDBC型からDerbyでの型を拾っていくことで

SQL Server型 JDBC型 Derby型
bit BIT 該当なし
int INTEGER INTEGER
nvarchar VARCHAR VARCHAR
NVARCHAR VARCHAR
datetime TIMESTAMP TIMESTAMP

みたいな。JDBCを介してSQL ServerとDerbyの型マッピングができるかなと。
BITのようにピンポイントで該当するものがない場合は、CHAR FOR BIT DATAやBOOLEANで代替可能か?を実際に確認しました。

で、確認・検証方法ですが、実際にデータベース、テーブルを準備して行いました。

気にしているのは、オンライン時にMS SQL Serverで保存されたデータがオフライン環境のApache Derbyへ格納されたり、その逆があったり、というのをJPAを介して問題なくできるか、という所です。
なので、実際Sync(同期)するときに利用するJAX-RSで各々で作成したデータをJSONで比較しあうことで検証しました。

というのも、同期はJSONでJava Entityオブジェクトベースに行うので、JSONが同じであれば、利用してるプログラムは同じなので、同じEntityになるはず、と。

f:id:kikutaro777:20140208193109p:plain

こういう検証の仕方で適切なのか、わからないのですが、実際にシステムを介して作成したデータ同士を比較できるので安心感はあるかなと。

Java EEを利用したオフラインWebシステム構築にChallenge! ~その1~

少し前に「オフラインのWebシステム構築」を調査・検証・プロト作成することになりました(^^;

実際に動くモノがだいぶ形になったので、少しずつ書いていこうかなと。

まずは、そもそもなんでそんなことをすることになったか…の背景から整理してみます。

オフライン機能への需要

お客さんからよく聞く要望

自分の所属組織では日頃、案件管理や販売管理のシステムを主に受託開発しています。

昔はWindows Formなどで開発するのがメインでしたが、最近だとイントラでの利用であってもWebシステムを求められることが多くなり、直近で開発したものはほとんどWebシステムでした。

で、案件管理とか販売管理システムは、実際の利用者(エンドユーザ)の方が営業担当者であったりするため

「出先でネットにつながらない場合もあるので、オフラインでシステムを利用したい。」

と言った話をよく聞きます。

また、私は実際に触ったことはないのですが、Salesforce CRMにもそういった機能があるので、よくある話なのかなと。

どんな状況下でも仕事ができるようにならねばならないとは大変だなぁと思いつつ(^^;

自分達でも欲しいケース

一方で、自分達でも欲しいときがあります(^^;

それはオフラインというよりは、手軽に起動できるWebシステム、なのかもしれませんが。

例えば、営業さんのサポートでWebシステムをデモする場合など、自分がデモする際にはノートPCに環境整ってるし特に困ることはないです。

ただ、営業の方が突如「単独でデモしたいんだけど!!」となった場合

  • 操作動画でデモしてもらう
  • VPNでつないでもらう
  • デモ対象のWebシステムを公開サーバに置く
  • その人のノートPCに環境を構築する

などなど選択肢は色々ありますが、最後の選択肢を求める人が多い気がします。

で、それなりの時間をかけて

環境準備して…

DB入れて…

APサーバ立てて…

と、環境構築するだけでそれなりに手間がかかりますし

「マシン変えた」…「他の営業にも同じ構築を」…「お客さんに貸し出す」…

などなど。手順書渡したりしても失敗したり、インストーラ作っても環境によって失敗しちゃったり。

究極的には「コピペすれば動く」くらいにもっていけると…と思ったり(^^;

組込系を上手く使うことで、この辺りも実現できるかと。

実現方法は?

オフラインと聞いて、自分がまず思い浮かぶのはhtml5を利用して…Web Storageを利用して…といったイメージです。

去年参加したhtml5j conferenceで、まさにそういう内容の話を聞きました。
http://events.html5j.org/conference/2013/11/sessions

セッションの動画が公開されてました!↓

ただ、私のいる環境ではまだhtml5でシステム提供をした経験がないし、詳しい人もいない…。

そうなると、完全にクライアント専用のGUIを新たに構築する…といった選択肢?
元々クライアントがWindows Formなどで、Webサービスと通信、みたいなクラサバで作っていれば、少し頑張ればいける気がしますが(^^;

でもそもそも提供したのがWebシステムだったりすると、エンドユーザさんとしては日頃見慣れたブラウザでの画面で操作できるのが良いわけで…。

で、去年からJava EEをメインに開発しているので、それ前提にした場合、どのように構築できるか?を模索してきました。

そこで

  • Embedded GlassFish
  • 組込みデータベース

を利用しつつ、いくつかの条件が揃えば実現できるのでは?ということで、実際にJava EE6で構築した運用システムのオフライン化を検証していきました。

現在作ってるもの

最終的には以下のような構成図の仕組みです。

f:id:kikutaro777:20140207202741p:plain

わりと素直な構成だと思うのですが、一番の問題点はオンラインとオフラインで異なるベンダのデータベースとなっている点です。

今回オフライン構築対象のWebシステムでは、もともとMicrosoft SQL Server 2012がDBとして使われていました。

であればオフラインでは、SQL Server 2012のLocalDBとかを選択するのが素直なのですが、まだ対応したJDBCドライバがないっていう…(-_-;
まあLocalDBは開発用って感じで実際に運用で使えるかどうか、その辺りも見えないのですが;

ちなみに今後JDBCドライバを設ける予定はありそうな感じの情報も。
http://connect.microsoft.com/SQLServer/feedback/details/771612/jdbc-support-for-localdb

この「異なるベンダのデータベース」と聞いて思い出すのは、よくオラクルさんのJava EEセミナーなどでちょこちょこ聞く「JPAを使うことでデータベースの差異を吸収」「JPQLを使うことでクエリ変更も不要」という売りです(^^;

思想は理解しつつも、実際は大変だろうなぁ、ってかそもそも1つのシステム内で異なるDBを複数使うことはあまりないよなー、と聞き流していたのですが、まさか使うシチュエーションになるとはっ(^^;

でも実際に上記構築をしてみて、JPQLを利用してて良かった…と思いました。
1箇所だけNative Queryで書かれた部分があったのですが、幸いそこはJPQLに書き換え可能だったので書き換えることで問題なくいけました。

ただ、この辺に関しては色々条件がそろわないと駄目(利用してる型とかストアドがないとか)で、そこらへんはまた別途まとめようかなと思います。

はじめてのWindows Azure ~NetBeansのコード生成でJPAからSQLデータベースへ~

昨日書いた

はじめてのWindows Azure ~SQLデータベース作成からNetBeansでの接続まで~

にて、AzureでSQLデータベースを生成して、NetBeansのデータベースサービスと簡単に連携できました。

ということは、ここからNetBeansの自動生成機能を使えば簡単にデータベース処理のWebアプリが作れるわけで、やってみました。

ここに来るとあまりAzure関係ないですね…(^^;
ちなみにWidnows 8 Proの64bitでJDK8、NetBeans7.4でGlassFish4.0にて行いました。

続きを読む

今更ながらJPAの楽観ロックを確認してみました

色んなところで既に書かれてるので、今日のは完全に自分向けのメモ(^^;

JPAの楽観ロック、知識としては知っていたのですが試したことなくて、ちょうどやる必要が出たので、まずは簡単なサンプルで確認してみました。

プログラムは営業系のシステムをイメージして、商談データがあって、2人の人が同じデータを取得して変更して更新してしまった、という流れです。

環境

環境はWindows 7上のNetBeans 7.3でJava EE 6 & JDK7、GlassFish3.1.2でEclipseLink2.3.2です。データベースはMicrosoft SQL Server 2008 R2。

テーブルは超簡易で以下のようなものです。

商談ID 商談名 Version 作成日 更新日
0 商談1だよ 0 2013-10-10 19:51:55.793 2013-10-10 19:51:56.060

Versionカラムは楽観ロック用に設けたものです。

動作

まず結果から。

サンプルアプリをデプロイして、ブラウザを2つ起動してアクセスします。

f:id:kikutaro777:20131010204737j:plain

f:id:kikutaro777:20131010204743j:plain

1つ目のテキストにDBにある商談ID「0」を指定して「読込」ボタンを押します。
DBから読み込んで商談名が表示されます。

f:id:kikutaro777:20131010204836j:plain

f:id:kikutaro777:20131010204840j:plain

IEのブラウザは「商談2なんです」と名称を書き換えます。
もう1つのFirefoxでは「商談3なんだよ!」と名称を書き換えます。

f:id:kikutaro777:20131010205017j:plain

f:id:kikutaro777:20131010205021j:plain

で、各々で「保存」ボタンを押下!

NetBeansではブレイクポイントで複数のスレッドが止まると以下のような歯車マークになります。
f:id:kikutaro777:20131010205241j:plain

NetBeansのマルチスレッドデバッグは過去に書いてました。
NetBeansでマルチスレッドデバッグ

oppFacade.edit(myOpp)という所でEJB側でDB保存処理されます。
成功したのでDBを確認します。

f:id:kikutaro777:20131010205402j:plain

保存されてますね。そしてVersionカラムの値が「1」とカウントアップされてます(^^)
ここに関しては後程。

ではもう1つのFirefoxから来たほうのスレッドに切り替えて

f:id:kikutaro777:20131010205504j:plain

保存処理を実行してみます。

f:id:kikutaro777:20131010205511j:plain

するとエラーに!

GlassFishをみると

f:id:kikutaro777:20131010205626j:plain

OptimisticLockExceptionとなっています(^^)取得した時点でVersionが0で、書き込もうとしたらVersionが既に1となっていたため、「誰かが書き込んだやろ」と判定した流れかと。

EJB使うとBean側ではjavax.ejb.EJBExceptionに成り代わってしまうのが悲しいですが、EJB側でちゃんとcatchすればいける…のかな多分(^^;未確認

@Versionアノテーション

やったことは単純で、2つだけです。

  • テーブルのカラムにintの「Version」を設ける
  • Entityの上記カラムに該当する項目に@Versionのアノテーションを付与する
@Column(name = "Version")
@Version
private int version;

だけです。すんなり思い通りに動いたので良かった(^^)

ちなみにEclipseLinkの楽観ロックに関する記述は以下でした。
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Locking#Optimistic_Locking
最後の1文に「java.sql.Timestamp型も使えるけど、numeric typeをおススメします」と書いてあるのが気になる(^^;

JDOM2で生成したXMLをJPAでXML型に突っ込む

前に自分で書いたJPAでDBのXML型を扱う関連の

ですが、その後、以下のとても参考になる情報を頂きました(^^;

で、先日、Javaで単純なXMLを出力する関連で

を書いて、その後、以下のとても参考になる情報を頂きました(^^;

なんか色々助けて頂いてばかりで恐縮です…(-_-;精進します。

で、そろそろ本実装なのですが、この2つを合わせて、まずは簡単にJDOM2で作ったXMLJPAでデータベースに書き込んでみました。

データベースは

DB:MS SQL Server 2012
JDBC:Microsoft JDBC Driver 4.0 for SQL Server

です。

とりあえずサンプルレベルとして、NativeQuery使ってinsert文をは以下のような感じに。

em.createNativeQuery("
  insert into HogeHogeTable   
  (HogeID,HogeResult,CreateUserId,UpdateUserId,CreateDate,UpdateDate)
  values
  (1, ?,'kikutaro777','kikutaro777',
    '2013-07-30 00:00:00.000','2013-07-30 00:00:00.000'
  );").setParameter(1, selectedXml).executeUpdate();

HogeResultがXML型のカラムです。

で、指定したselectedXMLという変数は以下2つメソッドを定義して試しました。
DocumentクラスはJDOM2のクラスです。

  • XMLをStringで扱う
private String getXmlStrFromDoc(Document doc){
    //XML宣言部(<?xml version="1.0" encoding="UTF-8"?>は除外するため、omitをtrueで指定)
    XMLOutputter xmlOut 
        = new XMLOutputter(Format.getPrettyFormat().setOmitDeclaration(true));
    return xmlOut.outputString(doc);
}
String selectedXml = getXmlStrFromDoc(selectedDoc);
  • XMLをChar[]で扱う
private char[] getXmlCharArrFromDoc(Document doc){
    //XML宣言部(<?xml version="1.0" encoding="UTF-8"?>は除外するため、omitをtrueで指定)
    XMLOutputter xmlOut 
        = new XMLOutputter(Format.getPrettyFormat().setOmitDeclaration(true));
        
    CharArrayWriter charArrXmlWriter = new CharArrayWriter();
    try {
        xmlOut.output(doc, charArrXmlWriter);
    } catch (IOException ex) {
        Logger.getLogger(ItemBusinessLogic.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    return charArrXmlWriter.toCharArray();
}
char[] selectedXml = getXmlCharArrFromDoc(selectedDoc);

JDOM2のXMLOutputterはoutputStringメソッドでStringにしたり、outputメソッドでOutputStreamやWriterで出力したりできるので便利ですね。

とりあえず、上記のどちらでも無事insertできました。

ただ、XMLの宣言部(<?xml version="1.0" encoding="UTF-8"?>)を入れるとinsertできなかったです。多分この辺ですが、今日は英語を読む元気ないので来週に…。

ちなみに最初Stringの例でやっていたときに、うまくinsertしたデータが切れてしまうケースがあって、あれっ、Stringの最大を超えた…?ん?ん?とか思って以下つぶやいたのですが

試しに巨大なXMLデータを生成してみたのですが、上記2つの例(StringとChar[])ともに、JDOMからXMLOutputterで吐き出す際にheapエラーになりました(^^;
そりゃそうだ。

データが切れたのは多分ですが単純に変なデータが入ってただけのようです。今日、どちらでも正常にinsertできることを確認できたので。

さて、サンプルはこの程度に、もう少し色々調べてちゃんと実装せねば。

DBのXMLデータ型なるものをJPAで扱える???お試し編

今日のはモヤっとした投稿になります…(^^;

2013/7/7追記
と書いてたのですが、モヤっとしてたことを「しんさんの出張所」ブログの以下記事が色々と明確にして下さいました(^^;ありがとうございます。

RDBXMLを扱う
http://d.hatena.ne.jp/shin/20130706

次の案件の話を聞いていたら、あるDBテーブルのカラムでXML型を使うみたいな話がありました。
恥ずかしながら一部のリレーショナルDBに「XML型」なるものがあることを初めて知ったのですが…。ちなみにMS SQL Serverです。
http://msdn.microsoft.com/ja-jp/library/ms189887(v=sql.90).aspx

で、これを使いたいという話があって

「え、そもそも、そんな型の値をJPAで取れるの?」

みたいな疑問が(^^;

とりあえず、いつも通りにテーブルからエンティティ作成の流れで試してみると動くものはできました。

まずはテーブル定義。型「xml」!個人的に見慣れないので何か斬新(^^;

create table xmlTable(
    id int,
    xmlVal xml,
    primary key(id)
)

で、適当にMSDNにあったサンプル的なレコード作成しました。

INSERT INTO XmlTable values(1,'')

ここからNetBeansでお決まりのウィザード「データベースからのエンティティ・クラス」を実行

f:id:kikutaro777:20130705210840j:plain
f:id:kikutaro777:20130705210845j:plain
f:id:kikutaro777:20130705210849j:plain

以下のようなEntityクラスが生成されました。

package jp.co.hoge.entity;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author kikutaro777
 */
@Entity
@Table(name = "xmlTable")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "XmlTable.findAll", query = "SELECT x FROM XmlTable x"),
    @NamedQuery(name = "XmlTable.findById", query = "SELECT x FROM XmlTable x WHERE x.id = :id"),
    @NamedQuery(name = "XmlTable.findByXmlVal", query = "SELECT x FROM XmlTable x WHERE x.xmlVal = :xmlVal")})
public class XmlTable implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "id")
    private Integer id;
    @Size(max = 1073741823)
    @Column(name = "xmlVal")
    private String xmlVal;

    public XmlTable() {
    }

    //setter,getter略
    //hashCode、equals、toString略    
}

で、Entityからレコード取得すると…

f:id:kikutaro777:20130705210929j:plain

と、普通に取れるわけですが、これだと色々うまみがない気が(^^;

この辺りをみるとEclipseLinkではDescriptorCustomizerクラスを使ってゴニョゴニョゴニョと書いてあってDocument型に入れてたりする。

というか…

そもそもXML型の利点って何なんだろう(^^;?

ってなってきたので、そこからやりなおさねば…。

今日聞いた話では、ツリーのような形式のデータを保存、復元することが目的で、その表現でXMLを利用する…という流れだったのですが、まず個人的には、オブジェクトをそのままシリアライズしてBLOBに突っ込んだりしてもいいんじゃないのかなぁ、と思ったり。

そしたらXMLファイルとして吐きたい、という要望もある様子。

うーん、なんか色々モヤモヤしてる…やはりXML型の具体的な使われ方とかをもっと調べてみなきゃ。

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村