001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.db; 017 018import org.opengion.fukurou.util.Closer; 019import org.opengion.fukurou.util.ApplicationInfo; 020 021import java.sql.Connection; 022 023import java.util.Locale; 024import java.util.Map; 025import java.util.HashMap; 026 027/** 028 * コネクションを共有して、トランザクションを実現します。 029 * 030 * 基本的には、TransactionTag で利用されますが、一部、このオブジェクトを 031 * 渡して、直接、利用するケースもあります。 032 * 033 * トランザクションがすべて完了した後で、realClose() メソッドを呼び出します。 034 * 一度でも、rollback が指定されていれば、ロールバックを行い、コネクションを 035 * 破棄します。それ以外で、commit が指定されていれば、コミットを行い、 036 * コネクションを、プールに戻します。どちらも指定されていなければ、 037 * コネクションプールに戻すだけになります。 038 * 039 * 考え方として、下記のような流れになります。 040 * <pre> 041 * TransactionImpl tran = new TransactionImpl( appInfo ) ; 042 * try { 043 * ・・・・・ 044 * tran.commit(); 045 * tran.finish(); 046 * } 047 * catch( Exception ex ) { 048 * tran.rollback(); 049 * } 050 * finally { 051 * tran.realClose() 052 * } 053 * </pre> 054 * 055 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 056 * 057 * @version 5.0 058 * @author Kazuhiko Hasegawa 059 * @since JDK6.0, 060 */ 061public class TransactionImpl implements Transaction { 062 //* このプログラムのVERSION文字列を設定します。 {@value} */ 063 private static final String VERSION = "5.3.8.0 (2011/08/01)" ; 064 065 private static final long serialVersionUID = 538020110801L ; 066 067 private static final String DBID = "DEFAULT"; 068 private final ApplicationInfo appInfo ; 069 070 private Connection defconn = null; // 最も利用率の高いDEFAULTだけ、別に変数を用意。 071 072 private final Map<String,Connection> dbidMap = new HashMap<String,Connection>(); 073 private boolean isCommit = false; 074 private boolean isRollback = false; 075 private boolean isError = false; 076 private boolean isFinish = false; 077 078 /** 079 * ApplicationInfo を指定して作成する、コンストラクター 080 * 081 * このクラスは、基本的には、TransactionTag クラスから作成されます。 082 * 083 * @param appInfo 内部統制用のアクセス情報 084 */ 085 public TransactionImpl( final ApplicationInfo appInfo ) { 086 this.appInfo = appInfo ; 087 } 088 089 /** 090 * 指定のDBID に対応した、Connection オブジェクトを返します。 091 * 内部Mapに存在していれば、そのコネクションを、存在しなければ、 092 * 新しく作成します。 093 * 094 * @param dbid 接続先ID 095 * 096 * @return 指定のDBID に対応した、Connectionオブジェクト 097 */ 098 public Connection getConnection( final String dbid ) { 099 if( dbid == null || dbid.length() == 0 || DBID.equalsIgnoreCase( dbid ) ) { 100 if( defconn == null ) { 101 defconn = ConnectionFactory.connection( DBID,appInfo ); 102 } 103 return defconn; 104 } 105 106 String udbid = dbid.toUpperCase( Locale.JAPAN ); // 大文字化 107 108 Connection conn = dbidMap.get( udbid ); 109 if( conn == null ) { 110 conn = ConnectionFactory.connection( udbid,appInfo ); 111 dbidMap.put( udbid,conn ); 112 } 113 114 return conn; 115 } 116 117 /** 118 * コミット処理が行われた場合に、内部フラグ(isCommit)を true にセットします。 119 * 1回でもコミットが行われており、ロールバックが行われていなければ、 120 * コミットされます。 121 * 122 * 検索処理のみで、エラーが発生していない場合は、コミットも行われないケースがあります。 123 * 124 * @return 正常:true/異常:false 125 */ 126 public boolean commit() { 127 isCommit = true; 128 return true; 129 } 130 131 /** 132 * ロールバック処理が行われた場合に、内部フラグ(isRollback)を true にセットします。 133 * 1回でもロールバックが行われていれば、最終的にはロールバックされます。 134 * 135 * ロールバック指定の場合は、isError フラグを true(エラー有)にセットします。 136 * 137 * @return 正常:true/異常:false 138 */ 139 public boolean rollback() { 140 isRollback = true; 141 isError = true; 142 return true; 143 } 144 145 /** 146 * トランザクションの、終了時処理を行います。 147 * 148 * 実質的には、なにもしません。 149 * 150 * @see #close( boolean ) 151 * 152 * @return 正常:true/異常:false 153 */ 154 public boolean close() { 155 return close( false ); 156 } 157 158 /** 159 * トランザクションの、終了時処理を行います。 160 * 161 * 引数は、正常かどうかを判定するフラグです。異常の場合は、true をセットします。 162 * ここでは、実際には何もしませんが、内部的にエラーフラグをセットします。 163 * (エラーの場合のみセット。リセットはされません) 164 * 一度でも、エラーが発生したコネクションは、破棄します。それ以外は、プールに戻します。 165 * 166 * @param errFlag [true:エラー状態/false:通常] 167 * 168 * @return 正常:true/異常:false 169 */ 170 public boolean close( final boolean errFlag ) { 171 if( errFlag ) { isError = true; } 172 return true; 173 } 174 175 /** 176 * トランザクションとして、正常終了時に処理を行います。 177 * 178 * 実質的には、内部のfinishフラグをセットするだけです。 179 * ただし、このフラグがセットされていない場合は、処理が途中で止まった 180 * 可能性があるため、トランザクションとしては、正常終了させることができません。 181 * 182 * @see #realClose() 183 */ 184 public void finish() { 185 isFinish = true; 186 } 187 188 /** 189 * トランザクションとして、終了時処理を行います。 190 * 191 * トランザクションがすべて完了した後で、呼び出します。 192 * 一度でも、Rollback が指定されていれば、ロールバックを行い、コネクションを 193 * 破棄します。それ以外で、Commit が指定されていれば、コミットを行い、 194 * コネクションを、プールに戻します。どちらも指定されていなければ、 195 * コネクションプールに戻すだけになります。 196 * 197 * @og.rev 5.3.8.0 (2011/08/01) 内部変数を初期化し、このオブジェクトが再利用できるようにする。 198 */ 199 public void realClose() { 200 if( defconn != null ) { 201 connClose( defconn,DBID ); 202 } 203 204 for( Map.Entry<String,Connection> entry : dbidMap.entrySet() ) { 205 String dbid = entry.getKey(); 206 Connection conn = entry.getValue(); 207 208 connClose( conn,dbid ); 209 } 210 211 // 内部変数を初期化します。 212 defconn = null; 213 214 // 5.3.8.0 (2011/08/01) 内部変数を初期化し、このオブジェクトが再利用できるようにする。 215// dbidMap = null; 216 dbidMap.clear(); 217 218 isCommit = false; 219 isRollback = false; 220 isError = false; 221 isFinish = false; 222 } 223 224 /** 225 * Connection オブジェクトをクローズします。 226 * 227 * 実際にはクローズせず、commit または、rollback を行った後、 228 * エラー状況に応じて、ConnectionFactory に返却するか、削除します。 229 * なお、commit または、rollback 時にエラーが発生した場合でも、無視して 230 * そのまま、処理を継続します。 231 * 232 * @param conn クローズ処理を行う、Connection オブジェクト 233 * @param dbid 接続先ID 234 */ 235 private void connClose( final Connection conn, final String dbid ) { 236 // まず、コミットかロールバックされた場合は、どちらかの処理が必要 237 if( isCommit || isRollback ) { 238 // commit できる条件:コミットされ、フィニッシュされ、エラーでなく、ロールバックでない 239 if( isCommit && isFinish && (!isError) && (!isRollback) ) { 240 Closer.commit( conn ); 241 } 242 // それ以外は、ロールバックする。 243 else { 244 Closer.rollback( conn ); 245 } 246 } 247 248 // 残りは、コミットもロールバックもされていないため、単にキャッシュへの返し方のみ判定する。 249 // isFinish されていないが、エラーにもなっていない場合は、接続要因以外の問題なので、返却でよい。 250 if( isError ) { ConnectionFactory.remove( conn,dbid ); } // 削除 251 else { ConnectionFactory.close( conn,dbid ); } // 返却 252 253 } 254}