[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 10511] Re: DB トランザク ション (度々 commit/rollback を書きたくない)



宮本@muimiです。

案2
別の方向からせめてみました。
DinamicProxy + ThreadLocal

ex.
-----------------------------------------------
ISomeLogic logic = (ISomeLogic)TransProxy.newInstance(new SomeLogic());
logic.doSomething();
-----------------------------------------------

イチイチCommandを作る手間がはぶます
(でもインターフェイスを作る手間はいる)
それなりに(クライアント)コードも見やすい。

でもこんなの自分で実装するぐらいなら、
EJBとか使った方が安全ですね。。。

JDKに
Collection#unmodifiedSet(Set)みたいな感じで、
ConnectionUtil#transactionMethod(Method)みたいなのあるといいのに


#みなさんは、どうやってコネクションを厳重に管理していますか?
#try/catchか?
#EJBか?
#はたまたAspectJか?


※以下、コード。度々長くてすんまそん
 長いと見る気しないっすね。
 でも今日が旬だったので、投稿します。

=============================
RequiredTransaction
スレッドにトランザクションをひもづけ
=============================
package db3;

import java.sql.*;

/**
 * CMTのRequiredライクなトランザクション
 */
public class RequiredTransaction {

  private Connection con;

  private int depth;

  private boolean isRollbackOnly = false;

  private static final ThreadLocal tl = new ThreadLocal();  
  
  private RequiredTransaction(){
    try {
      con = ConnectionManager.getConnection();
    } catch (SQLException e) {
      e.printStackTrace();
      throw new IllegalStateException(e.toString());
    }
  }
  
  public void beginTransaction() throws SQLException{  
    depth++;
  }

  public void endTransaction() throws SQLException{
    depth--;
    
    if(depth == 0){
      try{
        con.commit();
      }finally{
        try{
          con.close();
        }catch(SQLException e){
          //お手上げ
        }
      }
    }
  }

  public static RequiredTransaction getTransaction(){
    RequiredTransaction trans = (RequiredTransaction)tl.get();
    if(trans == null){
      trans = new RequiredTransaction();
    }
    
    return trans;
  }

  public void setRollbackOnly(boolean b){
    isRollbackOnly = b;
  }

  public static Connection getConnection(){
    return getTransaction().con;
  }

}



=============================
TransProxy
トランザクションをかけるDynamicProxy
=============================
package db3;

import java.lang.reflect.*;
import java.sql.SQLException;

public class TransProxy implements InvocationHandler {

  private Object obj;

  public static Object newInstance(Object obj) {
    return java.lang.reflect.Proxy.newProxyInstance(
      obj.getClass().getClassLoader(),
      obj.getClass().getInterfaces(),
      new TransProxy(obj));
  }

  private TransProxy(Object obj) {
    this.obj = obj;
  }

  public Object invoke(Object proxy, Method m, Object[] args)
    throws Throwable {
    Object result;
    try {
      System.out.println("before method " + m.getName());
      doStart();

      result = m.invoke(obj, args);

    } catch (Throwable e) {
      doCatch();
      throw e;

    } finally {
      System.out.println("after method " + m.getName());
      doFinally();
    }
    return result;
  }
  
  
  void doStart(){
    try {
      RequiredTransaction.getTransaction().beginTransaction();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  
  void doCatch(){
    RequiredTransaction.getTransaction().setRollbackOnly(true);
  }
  
  void doFinally(){
    try {
      RequiredTransaction.getTransaction().endTransaction();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }  
  
}



↑ここまで
以下補足


=============================
クライアント側
=============================
package db3;

public class Main {

  public static void main(String[] args) {

    //普通
    //SomeLogic logic1 = new SomeLogic();
    //logic1.doSomething();
    
    //トランザクション境界付
    ISomeLogic logic2 = (ISomeLogic)TransProxy.newInstance(new SomeLogic
());
    logic2.doSomething();
    
    System.out.println("END");
  }
}


=============================
クライアント側
DBアクセスビジネスロジック
=============================
package db3;

import java.sql.*;


public class SomeLogic implements ISomeLogic{

  public void doSomething(){

    Connection con = RequiredTransaction.getConnection();

    try{
      Statement smt = con.createStatement();
      smt.executeUpdate(
        "insert into cd values('sss2','sss2')"
      );
    }catch(SQLException e){
      e.printStackTrace();
    }

  }

}


=============================
クライアント側
DBアクセスビジネスロジックのインターフェイス
=============================
package db3;


public interface ISomeLogic {

  public void doSomething();
}