「恋するハニカミ!」

蛯原友里ちゃん,ほとんど出番なし.(;_;)
ちゃんとしたセリフもなかったし... 無念だ.
にしても,上の方から見下ろすようなシーンでは,友里ちゃんの脚がとってもほそーく見えます.さすが.
さぁ,この後は「プレミアの巣窟」だ!

「プレミアの巣窟」

...無念だ.
先週があまりにも素晴らしかっただけに,今週の「プレミアの巣窟」はちょっと物足りない感じ.(;_;)
というのもですね,ゲストにキャイーンウド鈴木が出てきて天野と二人ではしゃいでくれたおかげで,友里ちゃんが映る機会が減ってしまったのです.無念だ.
そのウド鈴木,登場の際に「ゼスプリゴールドキウイ・ヨーグルト」を持参して出演者全員に配ってました.そうなんです,友里ちゃんは昨年のゼスプリゴールドキウイ・イメージガール(ゼスプリンセスというらしい)なんですねぇ.坂口憲二が「あまい,あ〜まい」とかいいながらキウイを食べてて,最後の一つを彼女と取りあいになって,お皿からキウイを跳ね上げて奪っちゃうというCMを覚えていますか? あのかわいそうな女の子が友里ちゃんだったのです.友里ちゃん,最後はシルエットみたいになっちゃうんで,ファン的にはとても残念なCMでした...
そこまではいいとして,その後はキャイーンLiveの紹介ということもあり,ウドと天野が二人で漫才しちゃってる感じ.たまに友里ちゃんの笑い声なんかが聞こえるものの,画面に映らない時間が長く感じました.なんとなく「恋するハニカミ!」を見ているのと同じ感じ.漫才はお笑い番組でやってくれよっ!って思いました.ぐすん.
今週も健在の「Premiere Flush」では,またしても友里ちゃんの眼鏡姿を楽しむことができたのですが,ここでもキャイーンの二人がでしゃばってくるものだから,友里ちゃんもだんだん絶叫する羽目に.クールな大人のキャラを演じる設定だったと思われるのですが,全然違う方向(ヒステリック系?)に行っちゃいました.無念だ.
ちなみに友里ちゃん,今回の衣装は黒のタンクトップに白い膝丈のパンツ(カプリパンツっていうの?).大きなリング状のピアス付けてます.今日の「恋するハニカミ!」の衣装よりもこっちの方がいい感じ.
とにかくですね,ウド鈴木が出てきたおかげで先週に比べて満足度かなり低めです.もうゲスト呼ばなくていいよ.ずっと友里ちゃんを見せて欲しい!
本当,お願いしますよ.>番組関係の皆様
と,「プレミアの巣窟」オフィシャルサイトにも書いておこう.

お仕事スタイル

  • ネイビーのジップアッププルゾン(HERMES 02-03AW)
  • グレイッシュなブルーのカットソー(allegri 02-03AW)
  • ネイビーのベルベットパンツ(JIL SANDER 02-03AW)
  • 黒のスニーカー(TOM FORD FOR GUCCI 02-03AW)

今日は冷え込むとか言ってなかったっけ?
来るときすごーく蒸し暑かったんですけど.
このコーディネートもそろそろ終わりだなぁ.名残惜しい...

Spring Framework 入門記 Transactionその4 Declarative Transaction using Metadata

前回でトランザクション編は終わり,今回はメタデータだと宣言したのですが,「Chapter 7. Source Level Metadata Support」を見たところ,すでに「AOPその14」で学習済みのことがほとんどでした.無念だ.うーむ,「5.9.2. Using metadata-driven autoproxying」に7章へのリンクを張っておいてくれれば別途Commons Attributesを学習しに行かなくても済んだかもしれないのに... ま,いっか.
そんなわけで,改めて7章へ取り組むのはやる気Nullなのです.しかし日記である以上,何かしないわけにはいきません.ということで,メタデータを使った宣言的トランザクションをやってみましょう.5〜7章の集大成という感じです.というか,情報が散らばっていて困っちゃってるんですが.


AOPその14」で学習したように,Springでは現在のところApache Jakarta Commons Attributesを使ってメタデータを扱うことができます.Commons Attributesでは,次のようにソースにメタデータを埋め込みます.

/**
 * @@class(constructor-arg, property=value, ...)
 */

では,トランザクションを扱うのにどのようなclassを書くことができるかというと,次のものが用意されているようです.

  • org.springframework.transaction.interceptor.DefaultTransactionAttribute
  • org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
  • org.springframework.transaction.interceptor.RollbackRuleAttribute
  • org.springframework.transaction.interceptor.NoRollbackRuleAttribute

まず最初から.DefaultTransactionAttributeは一番単純なもので,コンストラクタ引数またはプロパティでPROPAGATION LEVELを指定することができます.省略するとPROPAGATION_REQUIREDになります.また,readOnlyなどのプロパティがあります.このメタデータ属性を使った場合,該当のメソッドが例外をスローすると,その例外がRuntimeExceptionまたはError(unchecked例外)ならロールバック,それ以外(checked例外)ならコミットとなります.
その次のRuleBasedTransactionAttributeは,メソッドが例外をスローした場合にロールバックするかしないかを設定できるもので,RollbackRuleAttributeおよびNoRollbackRuleAttributeと組み合わせて使用します.それぞれ,これまで使ってきた'-'や'+'に対応します.なんですが,RuleBasedTransactionAttributeのコンストラクタを見ると,PROPAGATION LEVELを設定するためのintのみを受け取るものがありません.プロパティで設定するしかないようです.
RollbackRuleAttributeおよびNoRollbackRuleAttributeは,コンストラクタで例外クラスを設定することができます.メソッドが該当の例外をスローすると,それぞれロールバックしたりコミットしたりすることを指定します.
このようなメタデータ属性をソースに記述して,Commons Attributes の Attribute Compiler で処理すればいいわけですね.


次に,そのようにして指定されたトランザクションの特性に従って制御をしてくれるAspectが必要です.この場合,すでに「Transactin その2」で学習済みのTransactionInterceptorをそのまま使えるようです.こいつは,メソッドJoinpointに対してどんな特性のトランザクションを制御するかを,TransactionAttributeSourceから取得します.ということで,メタデータで定義された属性を扱うための実装クラスが用意されています.それが

  • AttributesTransactionAttributeSource

です.そんなのもあったんですね.「Transactin その2」の時は気づきませんでしたよ.心より恥じる.
ということで,TransactionInterceptorAttributesTransactionAttributeSourceを組み合わせて autoproxy creator でターゲットにWeavingすることで,メタデータによる宣言的トランザクションができるということのようです.分かったような分からないような? 心より恥じる.
そんな場合は実践です.長々と能書きばかり書いてないで(いつもよりは短い気がしますが),実践あるのみ!


ということで,まずはトランザクショナルなクラス,おなじみのFooトランザクション属性を埋め込んでみましょう.これまでのTransaction編と同じ結果になるように指定してみました.

package study;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.sql.DataSource;

public class Foo {
    private DataSource dataSource;
    public DataSource getDataSource() {
        return dataSource;
    }
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    /**
     * @@org.springframework.transaction.interceptor.DefaultTransactionAttribute()
     */
    public void createTable() throws Throwable {
        Statement st = dataSource.getConnection().createStatement();
        st.execute("create table pair (key varchar, value varchar, primary key(key))");
    }
    /**
     * @@org.springframework.transaction.interceptor.DefaultTransactionAttribute(readOnly=true)
     */
    public String query(String key) throws Exception {
        Statement st = dataSource.getConnection().createStatement();
        ResultSet rs = st.executeQuery("select value from pair where key='" + key + "'");
        rs.next();
        return rs.getString(1);
    }
    /**
     * @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute()
     * @@org.springframework.transaction.interceptor.NoRollbackRuleAttribute(java.lang.UnsupportedOperationException.class)
     */
    public void insert(String key, String value, Throwable throwable) throws Throwable {
        Statement st = dataSource.getConnection().createStatement();
        st.execute("insert into pair (key, value) values('" + key + "', '" + value + "')");
        if (throwable != null) {
            throw throwable;
        }
    }
    /**
     * @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute()
     * @@org.springframework.transaction.interceptor.RollbackRuleAttribute(java.io.IOException.class)
     */
    public void update(String key, String value, Throwable throwable) throws Throwable {
        Statement st = dataSource.getConnection().createStatement();
        st.execute("update pair set value='" + value + "' where key='" + key + "'");
        if (throwable != null) {
            throw throwable;
        }
    }
}

createTable()およびquery()ではDefaultTransactionAttributeを指定しています.ともにPROPAGATION LEVELは指定していないので,デフォルトのPROPAGATION_REQUIREDになります.
query()ではさらに,readOnlyプロパティにtrueを指定しています.
insert()およびupdate()では,RuleBasedTransactionAttributeを指定しています.こちらもPROPAGATION LEVELは指定していないので,デフォルトのPROPAGATION_REQUIREDになります.
insert()にはNoRollbackRuleAttributeupdate()にはRollbackRuleAttributeを指定しています.ここで最後に ".class" なんて書いてあるのは,この部分がそのままソースファイルにコピペされるからで,その場合にちゃんとClassインスタンスへの参照になるわけです.
さて,次は定義ファイルです.「Transactin その2」の定義ファイルをベースにしました.

<bean id="actualDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
    <property name="url"><value>jdbc:hsqldb:.</value></property>
    <property name="username"><value>sa</value></property>
    <property name="password"><value></value></property>
    <property name="minIdle"><value>1</value></property>
</bean>

<bean id="dataSource" class="study.DataSourceWrapper">
    <property name="actualDataSource"><ref bean="actualDataSource"/></property>
</bean>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource"><ref bean="dataSource"/></property>
</bean>

<bean id="attributes"
    class="org.springframework.metadata.commons.CommonsAttributes"
/>

<bean id="txAttribute"
    class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
    <constructor-arg><ref bean="attributes"/></constructor-arg>
</bean>

<bean id="txInterceptor" 
    class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager"><ref bean="transactionManager"/></property>
    <property name="transactionAttributeSource"><ref bean="txAttribute"/></property>
</bean>

<bean id="debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>

<bean id="autoProxyCreator" 
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames"><value>foo</value></property>
    <property name="interceptorNames"><value>txInterceptor,debug</value></property>
</bean>

<bean id="foo" class="study.Foo">
    <property name="dataSource"><ref bean="dataSource"/></property>
</bean>

Transactin その2」のと異なっているのは,txAttributeAttributesTransactionAttributeSourceになっていることと,attributesが追加されていることくらいです.
これを,これまでと同じ実行用クラスでゴー!!!!

 Debug interceptor: count=1 invocation=[Invocation: method=[public void study.Foo.createTable 以下略
 Debug interceptor: next returned
  - Initiating transaction commit
 Debug interceptor: count=2 invocation=[Invocation: method=[public void study.Foo.insert 以下略
 Debug interceptor: next returned
 - Initiating transaction commit
 Debug interceptor: count=3 invocation=[Invocation: method=[public java.lang.String study.Foo.query 以下略
 Debug interceptor: next returned
 - Initiating transaction commit
 Ebihara
 Debug interceptor: count=4 invocation=[Invocation: method=[public void study.Foo.insert 以下略
 - Initiating transaction commit
 Debug interceptor: count=5 invocation=[Invocation: method=[public java.lang.String study.Foo.query 以下略
 Debug interceptor: next returned
 - Initiating transaction commit
 Yada
 Debug interceptor: count=6 invocation=[Invocation: method=[public void study.Foo.update 以下略
 - Invoking rollback for transaction on method 'update' in class [study.Foo] due to throwable [java.io.IOException]
 - Initiating transaction rollback
 Debug interceptor: count=7 invocation=[Invocation: method=[public java.lang.String study.Foo.query 以下略
 Debug interceptor: next returned
 - Initiating transaction commit
 Yada

よっしゃー!!
ということで,トランザクションメタデータあわせて7章まで完了だということにしてしまいましょう.強引? 心より恥じる.


今後の予定ですが,この週末は新たな学習はお休みして,ここまでの入門記をSpring Padにまとめようと思っています.Founderのjunoさんにも快く了承していただけたので,本家からリンクされているところで恥をさらす目立ってみようかと.むふふ.
ということで編集のルールとか見ていたのですが,結構はてなと違うものなんですね.手作業じゃやってられません.スクリプト書かねば.っていうかどこかに転がってるもの?
それから,この入門記の売りである「無念だ」「心より恥じる」を始めとするZaizen語録を残していいものかも悩み中.現在のSrping Padの雰囲気をぶち壊しそうですからねぇ.あとサンプル中に埋め込まれた特定タレントの名前も? うーむ.


そんなこんなで来週には「Chapter 8. DAO support」から再開して,GW明けくらいかなぁ,「Chapter 9. Data Access using JDBC」を終えた後は,「Chapter 10. Data Access using O/R Mappers」に突入する前に,そこで必要になるHibernateの入門記をやりたいと思います.ひがさんにつつかれているしぃ.(^^;
なのですが,今のところHibernateをどこからダウンロードすればいいかも知りません.無念だ.大丈夫か?>俺


あう! ここに来て,もっと大切なことを忘れていることに気づきました.昨夜リリースされた1.0.1へのバージョンアップを行わずにここまで書いてしまいました.なんてこった... 心より恥じる.