S2Hibernate で read only な Session

ちょっとした思いつき.
S2Hibernate を使うと,トランザクションのコミット前に Session#flush() を呼び出してくれます.
でも,大量の永続オブジェクトを読み込んだ場合など,Session#flush() は結構重い処理になりかねません.
そんなわけで (どんなわけで?),read only なセッションでは Session#flush() を呼び出さないようにできるといいかも.
ということでまずは S2Session にプロパティを追加!!

    public boolean isReadOnly();
    public void setReadOnly(boolean readOnly);

そして S2SessionImpl でこいつを実装!!

    private boolean readOnly_;

    public boolean isReadOnly() {
        return readOnly_;
    }

    public void setReadOnly(boolean readOnly) {
        this.readOnly_ = readOnly;
    }

S2SessionFactory#closeSession() でこいつをチェック!!

            if (session != null && session.isOpen()) {
                try {
                    if (!session.isReadOnly()) {
                        session.flush();
                    }
                } finally {
                    Connection con = session.close();
                    ConnectionUtil.close(con);
                }
            }

そして read only なセッションのためのインターセプタを作成!!

package org.seasar.hibernate.interceptor;

import net.sf.hibernate.FlushMode;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
import org.seasar.hibernate.S2Session;
import org.seasar.hibernate.S2SessionFactory;

public class ReadOnlySessionInterceptor extends AbstractInterceptor {
    private S2SessionFactory sessionFactory;

    public void setSessionFactory(S2SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        S2Session session = sessionFactory.getSession();
        session.setReadOnly(true);
        session.setFlushMode(FlushMode.NEVER);

        return invocation.proceed();
    }
}

こいつを s2Hibernate.dicon に追加!!

    <component name="readOnly" class="org.seasar.hibernate.interceptor.ReadOnlySessionInterceptor"/>

これでこんな風に使えます.

    <component name="..." class="...">
        <aspect>j2ee.requiredTx</aspect>
        <aspect pointcut="find.*">s2hibernate.readOnly</aspect>
    </component>

この場合は find で始まるメソッドだけが read only なセッションになります.
どうでしょう?>id:kenichi_okazaki さん


ちなみに Spring ではトランザクションのモードが read only だと Session#flush() しないことになっているようです.でもそれ,ちょっとイマイチな気のせいが.
例えば Hibernate で参照だけした結果を JDBC 直で更新する場合には無効だよねぇとか.
例えば RDB (Hibernate) は参照するだけなんだけど JMS を更新する場合には無効だよねぇとか.
なぜ JTA ではトランザクションに read only とかってモードがないかといえば,それはトランザクションよりもむしろリソースに設定するものだからだと思うのですよね.
まぁ,JTA 使うと JMS うまくいかない Spring ではあまり気にしなくていいのかもしれませんが.