EzJDBCのコード補完機能/いまさらvol.2


今回ご紹介するのは、EzJDBCのコード訪韓機能についてです。
今までも何度かEzJDBCはコード補完を利用するとほとんどタイプ(記述)することなくコードがかけますよ。と発信してきましたが、今回はもう少し具体的な説明をしたいと思います。


EzJDBCはJava1.6に対応してから、「new EzJDBC().select().from(CS)...」という記述方法をやめ、static import機能を利用して、「selects().from(CS)...」という記述方法にかわりました。
より、記述方法が単純になったわけです。照会したい場合は「selects()」、登録したい場合は「inserts()」、更新したい場合は「updates()」、削除し対場合は「deletes()」とだけ記述すればよいわけです(CREATEやDROP系は特殊なので、ここでは説明しません)。
しかし、その後に何を記述すればよいかは開発者が考えてタイプ(記述)しなければいけません。
EzJDBCでは、その点をEclipseの入力補完機能をフルに利用して、開発者をサポートするように出来ています。


では、以下の例を見てもらいましょう。
以下の画面では、照会系SQLを発行するためのコードをタイプ(記述)している途中です。
staticメソッドである「selects()」を呼び出した後に、Eclipseの補完機能を利用(Ctrl+Spaceを押下)して、次に呼び出せるメソッドを一覧で表示しています。

上記画面のサブウインドウの上側では、次に呼び出せるメソッドの一覧が表示されます。
サブウインドウの下側は、上サブウインドウで選択したメソッドの説明(JavaDoc)が表示されています。
上記例では、selects()メソッドの次に呼び出せるメソッドは3つだけが表示されており、2つめの(_from(Table))メソッドの説明が表示されています。
単純なSQLですので、誰にでもわかると思いますが、SELECT句の後に呼び出せるSQLはFROM句のみであるため、3メソッドだけが表示されているのです。


注意:3メソッドの説明

1._(Column... columns)メソッドは、selectメソッドで指定した列情報以外に取得する列を追加するメソッドです。
  通常のSQLには存在しませんが、機能的に便利なのでついています。
2._from(Table table)メソッドは、通常のfrom句の意味になります。引数にはテーブル情報を設定します。
3._from(Option subquery, String alias)メソッドは、from句にサブクエリーを設定するメソッドです。


では、次にfrom句の後に設定できるメソッドの一覧を見てみましょう。
2画面に分けて表示しますが、以下のような感じです。


その1

その2

一番初めに表示されている「_bind」メソッドは、ここでは説明を割愛しますが、from句の後に利用できるSQLに対応するメソッドのみ
が表示されているのがわかるかと思います。下ウインドウの説明には、SQLの説明と利用例が表示されていますので、悩まずに利用する
事が可能になります。
とはいっても、SQLを熟知している方は、こんな説明は読まずに「Ctrl+Space」押下、「↑↓」で選択し、「Enter」押下すれば、一切タイプすることなくSQLを組んで行くことが可能になります。


SQL初心者にとっては、単純なSQLならともかく普段利用しない関数を利用したい場合に、どこに記述すべきか迷うこともあるかと思いますが、EzJDBCでは、その関数が利用できる箇所にならないとメソッドが表示されませんので、自然にSQLの構文を理解する事が出来るようになります。メソッドの説明&例題を見ることによりSQL内で解決できる内容が増えてくるようになります。
SQL初心者にとっては、学習したけど忘れている関数を思い出せることや、素のSQLで良くあるタイプミスによるSQLエラーがなくなることが、一番の利点かもしれません。


EzJDBCのコード補完機能は、単にメソッド一覧を表示し入力を楽にするだけではなく、SQLのルールに基づいて記述する事を可能にする機能なのです...( ̄0 ̄)b

EzJDBCのテーブル結合方法と種類/今更ですが...


こんにちは、最近、6つのRDBMSとたわむれている高橋です。
そんな私が本日ここに各内容は、凝りもせずにEzJDBCの結合についてです。
私が今まで書いてきたEzJDBCを利用したテーブル結合のサンプルソースは以下のようなものでした。


CUSTOMER(CS), ORDERS(OD), ORDER_ITEM(OI)の3テーブルを結合し、結果を取得するEzJDBCのコード

 List list = selects().from(CS).join(OD, OI).find(Customer.class);


上記コードを記述するとEzJDBCはRDBMSに、以下のSQLを発行します。

SELECT
    CS.CODE,
    CS.NAME,
    CS.VERSION,
    OD.ORDER_NO,
    OD.CUSTOMER_CODE,
    OD.CREATED,
    OI.ORDER_NO,
    OI.SEQ
FROM
    CUSTOMER as CS left join
       ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join
       ORDER_ITEM as OI on (OD.CUSTOMER_CODE=OI.CUTOMER_CODE and OD.NO=OI.ORDER_NO)

Javaのコードでは、テーブルの結合条件を記述していませんが、この理由は以前説明した「2009-10-05 - T.RYoken がんばる日記 / TryGun blog」で事前に設定してあるためです。
このテーブル定義書で設定する結合はER図で設計する基本となる結合を設定することになります。
当然の伊ことですが、実開発では基本の結合条件だけでは足りない実情です。
しかし、新しい結合が出てくるたびにテーブル定義書に結合条件を追記し、コードジェネレーターにテーブル定義書を食わせる。なんてのはフレキシブルじゃない。
でも大丈夫!EzJDBCはテーブル結合条件もタイプ&ネームセーフにコードで実現できてしまうのです。


実際にCUSTOMER(CS), ORDERS(OD), ORDER_ITEM(OI)の3テーブルの結合条件をコードで書いてみましょう。

List list = selects().from(CS)
         .join(OD).on(CS.code.eq(OD.customerCode))
         .join(OI).on(CD.code.eq(OI.customerCode).and(OD.no.eq(OI.orderNo)))
         .find(Customer.class);

コレだけです。
SQLそのままですね。しかし、IDEのコード補完機能が使えますので、ほとんど「Ctrl+space」だけで記述可能になります。
また、タイプ&ネームセーフですので、SQLコードの間違いや、テーブル・列名の間違いは発生しないのです ... ( ̄0 ̄)b
また、結合条件にリテラルを指定することも可能です。


次に結合の種類ですが、EzJDBCでは4種類の結合をサポートしています。
・左外部結合 : left outer join
・右外部結合 : right outer join
・内部結合 : inner join
・全外部結合 : full outer join


通常サンプルで利用している「selects().from(CS).join(OD)」等のjoinメソッドは「左外部結合:left outer join」になります。
以下に各結合条件に対応するEzJDBCのメソッドを記述します。


・左外部結合 : selects().from(CS).join(OD)
・右外部結合 : selects().from(CS).rightJoin(OD)
・内部結合  : selects().from(CS).innerJoin(OD)
・全外部結合 : selects().from(CS).outerJoin(OD)


SQLそのまんまですね。だからこそ簡単に利用可能なのです。
EzJDBCでSQLを記述する本当のメリットは、まだ紹介できませんが、全機能が、今回説明したテーブル結合のようにIDEの補完対象となり、
タイプ&ネームセーフとなるため、簡単にかつ安全にデータの取得を行うことが可能になるのです。


簡単かつ安全なO/RマッパーがEzJDBCなのです....( ̄0 ̄)b

EzJDBCで危険な香りのするSQLを検知する機能!vol.2/調子に乗って...


こんにちは、EzJDBCはSQLを意識したO/Rマッパーなので、既存のSQLの知識もいかせて良いですよーとほざいては空ぶってばかりいる高橋です。
そんな私が、今回ご照会するのはEzJDBCで危険な香りがするSQLを検知する機能 VOL.2 です。
ところで、危険な香りがするSQLとは、どんなSQLなのでしょうか?
ずばり、ORDER BY句が指定されていないSQLなのです...
ORDER BY句が指定されていないSQLは無条件に危険とは言えないかもしれませんが、かなりの確立で危険度が高いSQLであることは間違いありません。
何故なら、ORDER BY句のないSELECTの、取得する結果の順番は不定となるからです。
そこで、EzJDBCまたはEzTxを利用してSQLを発行した場合は、SELECTのSQLにORDER BY句が指定されていない場合にWarningメッセージを出力する機能を提供します。
それでは、ORDER BY句が指定されていないSELECTのSQLが発行された場合に、SQLログにワーニングメッセージを出力する場合の例を見てみましょう。


Javaコード
CUSTOMER, IRDERS, ORDER_ITEMの3テーブルを結合し、結果を取得するEzJDBCのコード

 List list = selects().from(CS).join(OD, OI).find(Customer.class);


上記コードの実行結果のSQLログ
青字のログがSELETC文のSQLのORDER BY句が含まれていなかった時に出力されるログです。
赤字について説明します。
1.ログレベル「WARN」で出力されます。
2.ORDER BY句のついていないSQLを出力します。
3.2のSQLが発行された時刻をと応答時間を出力します。この情報により、どの処理で呼び出されたSQLかが判別可能になります。
赤字以降のログは、考えられる改善策が出力されます。

[16585653] DEBUG 2010-11-15 18:09:52.546 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-15 18:09:54.656 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-15 18:09:54.875 [main] SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
[16585653] WARN 2010-11-15 18:09:54.953 [main] SELECT文にORDER BY句未設定の警告 ...

                                                                                                                                                                  • -

下記のSQLにORDER BY句が未設定です。
ORDER BY句のないSELECTの、取得する結果の順番は不定となります。対象となるSQL文 : SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
SQLが発行された時間は、「2010-11-15 18:09:54.875」です。

                                                                                                                                                                  • -

【考えられる改善策】
1.ORDER BY句で結果の順番が一定になるように並び順を指定してください。
ORDER BY句で指定するソートの順番はユニークになる様にしてください。
2.抽出条件に一位の条件を指定している場合や、取得結果の並び順の指定を必要としない場合。
EzJDBCのorderByNothingメソッドを呼び出し、ORDER BY句が不要であることを明示して下さい。

[16585653] DEBUG 2010-11-15 18:09:55.265 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] コミットしました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] トランザクションを終了しました

単なるORDER BY句の付け忘れであれば、EzJDBC#orderByメソッドで並び順を指定すればよいことになります。
しかし、常に取得結果が1件の場合や処理的に並び順を考慮する必要が無い場合もあるかと思います。
その場合は、毎回警告が出力されるのは良くありませんので、明示的にEzJDBC#orderByNothingメソッドを呼び出します。


Javaコード
並び順を合えて指定しない場合のコード例

 List list = selects().from(CS).join(OD, OI).orderByNothing().find(Customer.class);


上記コードの実行結果のSQLログ

[16585653] DEBUG 2010-11-15 18:23:08.718 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-15 18:23:10.687 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-15 18:23:10.890 [main] SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
[16585653] DEBUG 2010-11-15 18:23:11.265 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] コミットしました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] トランザクションを終了しました

警告が出力されなくなりました。
警告を出力しないためにorderByNothingメソッドをわざわざ呼び出すことに面倒だと感じた方もいるかと思います。
しかし、orderByNothingメソッドを明示的に記述するには意味があります。システムの保守フェーズの際にORDER BY句が指定されていないのが潜在バグなのか、意味があることなのかをコードから
保守担当者に伝えるためです。
また、本当にORDER BY句の指定を忘れてしまった時には、開発段階で潜在バグ化する可能性のあるコードを気づかせることが出来ます。



このように危険度の高いSQLを開発段階から潰すことが可能に


するのが、EzJDBCなのです....( ̄0 ̄)b

EzJDBCで危険な香りのするSQLを検知する機能!


こんにちは、最近日記からすっかりナリを潜めていた高橋です。
別に誰からも相手にされないからといってスネていた訳ではなく、今度仕事で利用する某社のJavaフレームワークを調査・学習していたため、EzServlet&EzJDBCの開発があまり進まなかっただけです。
そんな私が、今回ご照会するのはEzJDBCで危険な香りがするSQLを検知する機能です。
ところで、危険な香りがするSQLとは、どんなSQLなのでしょうか?
ずばり、SQL応答時間が悪い(遅い)SQLなのです...
SQL応答時間が悪い(遅い)SQLは無条件に危険とは言えないかもしれませんが、危険度が高いSQLであることは間違いありません。


そこで、EzJDBCまたはEzTxを利用してSQLを発行した場合は、SQL応答時間が、ある一定の閾値(しきい値)を超えるとWarningメッセージを出力する機能を提供します。
閾値しきい値)はEzTx.propertiesのキー「SQL_RESPONSE_TIME_THRESHOLD_MILLI_SECOND」にミリ秒を設定することで指定します。
では、SQL応答時間が0.3秒を超えたら危険度が高いSQLとみなして、ワーニングメッセージをSQLログにワーニングメッセージを出力する場合の例を見てみましょう。


EzTx.propertiesで閾値(ミリ秒)の設定を行います。(設定を消すか、値に0以下を設定すると、チェックは行わなくなります)

# SQL応答時間ワーニングメッセージ出力閾値(ミリ秒)
SQL_RESPONSE_TIME_THRESHOLD_MILLI_SECOND = 300

Javaコード
3テーブルを結合しGROUP BYで集約・加算した2つのSQLをUNIONで結合し、最後にORDER BYで並べ変えを指定する。
また、それぞれのSQLの抽出条件の比較値を動的パラメータで指定したコードを実行する。

// 1つ目のSQL
EzJDBC jdbc1 =
       selects(CS.name,CS.code,CS.version.sum()).from(CS).join(OD,CI)
       .where(CS.name.between("'A", "Z"))
          .and(CS.code.ge(0).or(CS.code.le(100)))
          .and(OD.created.eq(null))
       .groupBy()
       .orderBy(CS.name.ASC, CS.code.DESC,CS.version.DESC);


// 2つ目のSQL
EzJDBC jdbc2 =
       selects(CS.name,CS.code,CS.version.sum()).from(CS).join(OD,CI)
       .where(CS.name.between("'A", "Z"))
          .and(CS.code.ge(0).or(CS.code.le(100)))
          .and(OD.created.eq(null))
       .groupBy();


// UNIONで結合しSQLを発行List list = jdbc1.union(jdbc2).find(Customer.class);

上記コードの実行結果のSQLログ
青字のログがSQL応答時間が0.3秒を超えたときに出力されるログです。
赤字について説明します。
1.ログレベル「WARN」で出力されます。
2.設定しきい値が出力されます。今回の例ですと0.3秒(300MS)が、しちい値として出力されます。
3.しきい値を超えたSQLを出力します。
4.3のSQLが発行された時刻をと応答時間を出力します。この情報により、どの処理で呼び出されたSQLかが判別可能になります。
赤字以降のログは、考えられる改善策が出力されます。今回は、複数テーブルを結合し、集約:加算してた結果をunionで結合したSQLですので少々複雑です。
このような時は、パラメータマーカーがボトルネックになる場合がありますので、下記の改善策にあるbindメソッドを利用して、比較値をSQL文に直接指定する方法を試した見たいと思います。

[16585653] DEBUG 2010-11-01 16:05:15.609 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-01 16:05:17.437 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-01 16:05:17.656 [main] SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between 'A' and 'Z' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE UNION (SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between '1' and '9' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE) ORDER BY NAME ASC, CODE DESC, VERSION DESC
[16585653] DEBUG 2010-11-01 16:05:18.078 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-01 16:05:18.078 [main] コミットしました
[16585653] DEBUG 2010-11-01 16:05:18.078 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-01 16:05:18.078 [main] トランザクションを終了しました
[16585653] WARN 2010-11-01 16:05:18.421 [main] SQL応答時間の警告 ...

                                                                                                                                                                  • -

下記のSQL応答時間しきい値(300ミリ秒)を超えました。
対象となるSQL文 : SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between 'A' and 'Z' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE UNION (SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between 'A' and 'Z' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE) ORDER BY NAME ASC, CODE DESC, VERSION DESC
SQLが発行された時間は、「2010-11-01 16:05:17.656」です。SQLの実行時間は、「422ミリ秒」です。

                                                                                                                                                                  • -

【考えられる改善策】
1.SQLのチューニングを行う。
  ・SUBQUERY, JOIN, UNIONを利用している場合は、SQLを見直すことにより改善する場合もあります。
  ・SUBSTR等の関数を利用している場合はレスポンスが極端に低下する場合があります。一度関数を排除したSQLでレスポンスを調査してください。
  ・ORDER BYの指定がレスポンスを悪化させている場合があります。昇順、降順の見直しが可能か検討してください。
  ・上記SQLCSE等のSQLツールで実行してレスポンスタイムを計測してみてください。レスポンスが良かった場合はパラメータマーカー(?)の利用をやめ比較値をSQL文に埋め込事によりレスポンスが改善されると思われます。
   EzJDBCを利用している場合はbindメソッドを呼び出して下さい。bindメソッドを呼び出すと比較値をSQLに埋め込んだSQLを実行します。
   注意:EzJDBC以外で、SQLに比較値を埋め込む場合はSQLインジェクションが起こらない様に細心の注意を払ってください。
  ・Viewやindexの作成を検討してみてください
2.RDBのチューニングを行う。
  ・DBAに相談のうえチューニングを検討して下さい。

Javaコード
抽出条件の比較値をSQL文に埋め込むbindメソッドを設定します。

// 1つ目のSQL
EzJDBC jdbc1 =
       selects(CS.name,CS.code,CS.version.sum()).from(CS).join(OD,CI)
       .bind()
       .where(CS.name.between("'A", "Z"))
          .and(CS.code.ge(0).or(CS.code.le(100)))
          .and(OD.created.eq(null))
       .groupBy()
       .orderBy(CS.name.ASC, CS.code.DESC,CS.version.DESC);


// 2つ目のSQL
EzJDBC jdbc2 =
       selects(CS.name,CS.code,CS.version.sum()).from(CS).join(OD,CI)
       .bind()
       .where(CS.name.between("'A", "Z"))
          .and(CS.code.ge(0).or(CS.code.le(100)))
          .and(OD.created.eq(null))
       .groupBy();


// UNIONで結合しSQLを発行List list = jdbc1.union(jdbc2).find(Customer.class);

上記コードの実行結果のSQLログ

[16585653] DEBUG 2010-11-01 16:19:24.468 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-01 16:19:24.484 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-01 16:19:24.484 [main] SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between ''A' and 'Z' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE UNION (SELECT CS.NAME,CS.CODE,SUM(CS.VERSION) as VERSION FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO) WHERE CS.NAME between '1' and '9' AND (CS.CODE>=0 OR (CS.CODE<=100)) AND (OD.CREATED is null) GROUP BY CS.NAME,CS.CODE) ORDER BY NAME ASC, CODE DESC, VERSION DESC
[16585653] DEBUG 2010-11-01 16:19:24.625 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-01 16:19:24.625 [main] コミットしました
[16585653] DEBUG 2010-11-01 16:19:24.625 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-01 16:19:24.625 [main] トランザクションを終了しました

赤字を参照してください。赤字の差がSQL応答時間になります。
発行時間が「16:19:24.484」で、完了時間が「16:19:24.625 」になりますから、
SQL応答時間は「141ミリ秒」となります。
改善前は「422ミリ秒」でしたから、かなり改善されましたね(^^)


このように危険度の高いSQLを開発段階から潰すことが可能になるのが、EzJDBCなのです....( ̄0 ̄)b

Java/愛の虹?


風の通る坂道、木漏れ日の階段に、思い出を刻んで、すべてJavaにする。
眩しさに目を閉じた、また、そのしぐさの中、新しいJavaひとつ見つけられたみたいだ。
永遠を探しに行こうなんて言わない。明日もずうと、その先もJavaといたいだけ...


Javaにふれてきらめきだす七色のフェーズ...強く...そっと...からむ...指に...熱を感じてる
どんな顔で、どんな声で、つたわるかなぁ...
時をとめる...このままもっと...ふたり...


JavaがTryGunにくれる優しさにふれるたび、思いはあふれてく、伝えきれないほど...
空を仰ぐ振りをして、隠したその涙を、TryGunの手でぬぐいたい、抱きしめられぬなら...
別れを知らない出会いなんて無いけど、それでもJavaが笑うなら、TryGunはいるから...


二つの音重なり合う七色のフェーズ...夢を...乗せて...音は...強く...時を奏でてる
あたり前の事はないよ、その全てが...
奇跡の様で、この手をもっと強く...
揺るがないもの、守りたいもの、JavaがTryGunを強くさせるよ...


Javaにふれてきらめきだす七色のフェーズ...強く...そっと、からむ...指に...熱を感じてる
どんな顔で、どんな声で、つたわるかなぁ...
時をとめる...このままもっと...
二つの音、重なり合う七色のフェーズ...夢を...乗せて...音は...強く...時を奏でてる
あたり前の事はないよ、その全てが...
奇跡の様で、この手をもっと強く...ずっと...七色のフェーズ...二人...七色のフェーズ...ずっと...



(*1) Java=君
(*2) TryGun=僕
(*3) フェーズ(要件・外部・内部・実装・単体・結合・総合)=フレーズ

何故だ〜!!!


こんにちは、JDBC関連のプログラムばかり作っては捨て、作っては捨ての作業を繰り返しトライ&エラーのスペシャリストになりつつある高橋です。トライ&エラーのスペシャリストって、たんなるダメダメプログラマーなんですけどね...(^^;)


以前「夢を見たい年頃です。。。」のエントリーにも書いた通り、その実力も資格も無い私ですが、少しだけ世界のシッポがみえてきましたよ。
EzJDBCの開発の中で生まれた「トランザクション管理機能」の「EzTx」のレスポンスが、いつの間にか世界レベルに達していました。
何をもって世界レベルに達しているといっているのか!
実際に世界中のトランザクション機構のベンチマークと比較したのか!そんなの無理ではないか、愚か者め!!!とお思いの方もいると思います。
実際問題として世界中の(Javaの)トランザクション機構のベンチマークを取得することは出来ませんが、オープンソースであれば可能でしょう。
とはいっても、今回はもっと良い方法をみつけましたので、そちらと比較しました。


最適化したJDBCプログラムと比較するのが一番手っ取り早いのです。
世界に幾つトランザクション機構が存在したとしても、Javaである限り、最適化したJDBCプログラムより高速のトランザクション機構は存在しえません。
だって、Javaで開発しているわけだから。。。(注:RDBMS自体にネイティブなJDBCを開発した場合は可能でしょうけど...ベンダー以外ありえない)


そんなわけで、
今回は10,000のSELECTを発行した時のパフォーマンスを、「最適化したJDBCプログラミング」と「EzTxを利用したプログラム」で比較しました。
処理結果は、それぞれ10回行なった平均です。


1.最適化したJDBCプログラミング

// ドライバーをロードします
Class.forName("com.ibm.db2.jcc.DB2Driver");
// コネクション取得
Connection connection = DriverManager.getConnection("TG3DB","","");
// 処理時間を計測するインスタンス生成(ミリ秒).結果をシステムアウト(true)
EzStopWatch w = new EzStopWatch(2).systemout(true);
// 処理時間計測開始
w.start();
// プリペアステートメントを取得します。プリペアを使い回すためloopの外で取得します。
PreparedStatement ps
   = connection.prepareStatement("SELECT * FROM CUSTOMER WHERE ID = ?");
// 10000回処理を繰り返します=1万回SQLを発行します。
for(int i=0; i<10000; i++) {
   ps.setInt(1,i);
   Resultset rs = ps.executeQuery();
   rs.next();
   rs.close();
}
// 処理時間計測終了
w.stop();
// プリペアステートメント・クローズ
ps.close();
// コネクション・クローズ
connection.close();
 
注意:クラスロードやキャッシュを考慮して、事前に1回処理してから計測しています。


最適化したJDBCプログラムでは、コネクション取得およびクローズは計測時間にいれていません。
また、同一SQLの場合はPreparedStatementを使いまわしたほうが良いため、PreparedStatementの生成はループの外で1回だけ行なっています。


【実行時間】

2,786 ミリ秒


2.EzTxを利用したJDBCプログラミング

// 処理時間を計測するインスタンス生成(ミリ秒).結果をシステムアウト(true)
EzStopWatch w = new EzStopWatch(2).systemout(true);
// 処理時間計測開始
w.start();
// トランザクション開始
EzTx.begin();
// 10000回処理を繰り返します=1万回SQLを発行します。
for(int i=0; i<10000; i++) {
   // コネクション取得
   Connection connection = EzTx.getConnection();
   PreparedStatement ps
    = connection.prepareStatement("SELECT * FROM CUSTOMER WHERE ID = ?");
    ps.setInt(1,i);
    Resultset rs = ps.executeQuery();
    rs.next();
    rs.close();
    ps.close();
    connection.close();
}
// トランザクション終了
EzTx.end();
// 処理時間計測終了
w.stop();

注意:クラスロードやキャッシュを考慮して、事前に1回処理してから計測しています。


EzTxを利用したプログラムでは、トランザクションの開始(EzTx.begin)から計測時間に含めています。
また、コネクションの取得(EzTx.getConnection)とPreparedStatementの生成は、あえてループ内で行なっています。明らかに、最適化したJDBCプログラムよりも、不利な状況で計測を行なっていることに注目してください。この理由は、同一トランザクション内で複数のテーブルを参照する場合、クラスをまたがって同じコネクションを利用する必要があります。
その様な時に、EzTx.getConnectionメソッドは、どのクラス(インスタンス)から呼び出しても同一のコネクションを返してくれます。その様な状況を加味して、あえて不利なコードを書いています。

実行時間は、「ログ未出力バージョン」と「ログ出力バージョン(非同期)」の2種類だしています。


【ログ未出力の実行時間】

2,095 ミリ秒


な、何故だ???EzTxのほうが最適化したJDBCより早い...( ̄口 ̄|||)


【ログ出力の実行時間】

2,247 ミリ秒

トランザクションログ】

DEBUG 2010-08-05 12:38:08:296 [main] トランザクションを開始しました
DEBUG 2010-08-05 12:38:08:296 [main] コネクションを取得しました(JDBC接続)
DEBUG 2010-08-05 12:38:08:296 [main] SELECT * FROM CUSTOMER WHERE ID = 0
DEBUG 2010-08-05 12:38:08:296 [main] SQLの実行が完了しました
9998回分のログ...
DEBUG 2010-08-05 12:38:10:546 [main] コネクションを取得しました(JDBC接続)
DEBUG 2010-08-05 12:38:10:546 [main] SELECT * FROM CUSTOMER WHERE ID = 9999
DEBUG 2010-08-05 12:38:10:546 [main] SQLの実行が完了しました
DEBUG 2010-08-05 12:38:10:546 [main] コミットしました
DEBUG 2010-08-05 12:38:10:546 [main] コネクションを返却しました。
DEBUG 2010-08-05 12:38:10:546 [main] トランザクションを終了しました

非同期ログを出力しても、最適化したJDBCより早い...(。。し)
な、何故だ〜!!!!( ̄口 ̄|||)

花見川諸島で何が悪い!


日本のアーキテクチャは、ガラパゴス化されているため世界標準じゃない。世界から遮断された現状では、今以上の発展はありえない。
とかいっている奴は、勘違いしている。
発展しない理由が、ガラパゴス化によるものなんて、まったく本質ではない。
発展しない本質は、物が良くないからだ。少し乱暴な言い方ではあるが答えはこれしかない。
違う言い方をするのであれば、技術の成熟度が薄いからとも言えるだろう。決してガラパゴス化のせいではない、その証拠として日本の食品業界はガラパゴス化の中で生まれたものが世界標準になっているものが多い。この事実はガラパゴスの世界で成熟した(独自進化した)結果が、良い物として世界に認められた事を証明している。


日本の食品で世界に認めれている物として、直ぐに思いつくのは、ソイソース(醤油)でろう。
醤油以外にも、「ネリわさび」や「ガリ(生姜)」等も世界で認められている。近年の製品では「マヨネーズ」が日本で独自進化し、世界に認められた製品だ。
マヨネーズは西洋のソースだろう?と思われた方も多いだろうが、日本のマヨネーズは西洋のソレとはことなり、明らかに日本独自文化の中(ガラパゴス化)で、進化したソースである。まず味がまったく別物である。
日本のマヨネーズは甘さを控え、酸味が加えられている。そして、コクを出すために卵の全てを使うのではなく卵黄しか利用しないといった徹底した独自進化ぶりだ。
次に、容器の進化である。西洋ではマヨネーズの器は瓶であり、取り出す時には、スプーンなどですくいだすのが一般的だが、日本のマヨネーズの器は、あの独特な容器である。手を汚さずに好きな分量をかける事が出来るすぐれものである。味、器の両方が世界で認められている。


調味料以外でも食品部門では、日本で独自進化した製品が海外に認められている。
ラーメンなどは、その代表的名ものであろう。最近は、日本の有名ラーメン店が海外に進出して成功をおさめた話もチラホラ聞こえてきているが、昔から世界に認められた製品としてラーメンは存在する。いわゆる即席麺である。
袋の即席麺からはじまり、カップ型の即席麺のすべてが世界で認めれている。
日本以外で、即席麺をここまで進化させた国は他にあるだろうか。味にこだわり、値段にこだわり、器にこだわる。挙句にはカロリーや健康にこだわる。
即席麺の位置づけとしては、こだわりすぎ、やりすぎとしか思えない追求ぶりだ。
日清とまるちゃんがカップめんの器の裁判で争った経緯があるほどのコダワリが、そこにはある。
しかし、このこだわりすぎ、やりすぎが世界で認められた要因でもある。
そういえば、本当かどうかは知らないが、ダイソンの社長がCMで日本人の追求する姿勢を見習って、ダイソンの掃除機を追及して作った。とか言っている。
日本人の追求する(こだわる)する姿勢は、世界でみとめられているのだ。


で、結局なにがいいたいのかというと、ソフトウェア業界は他の業界と比べると追求する(こだわる)姿勢が淡白な気がする。
世界標準が必ずしも良い物ではない。特にソフトウェア業界は日進月歩の勢いでいまだに進化を続けている。いわゆる常時不安定状態にある。
そのような世界で、世界標準といわれているものが次々と出てきても、それは机上の空論である場合が多い事に気がついて欲しい。
まれに実績ベースで世界標準になるものがでてくるが、それは新技術ではなく枯れた技術である場合がほとんどである。
そういった状況下で、○○標準にしなければと考えると縛りが増えるだけでなんのメリットもない世界が出来上がり、モチベーションなんかは北極星のかなたまで吹っ飛んでしまう。
プログラム言語も同様である。設定ファイルで疎結合を歌いXML地獄を生み出した。そんなXML地獄から救ってくれたのが、規約ベース開発だ。
しかし、全てを規約で作り上げたため、今度は規約地獄が世にはびこった。今では、規約地獄から開発者を救うべく、アノテーション地獄を作り上げようとしている。


で、やっぱり何が言いたいのかというと…ガラパゴス諸島ではなく花見川諸島で進化したTryGun3(EzServlet,EzJDBC)いいすよ。って言う自社へのアピールかよ( ̄O ̄し)