📄 embedxaconnection.java
字号:
/* Derby - Class org.apache.derby.jdbc.EmbedXAConnection Copyright 2003, 2005 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.jdbc;import org.apache.derby.iapi.store.access.xa.XAXactId;import org.apache.derby.iapi.store.access.xa.XAResourceManager;import org.apache.derby.iapi.store.access.XATransactionController;import org.apache.derby.impl.jdbc.Util;import org.apache.derby.impl.jdbc.EmbedConnection;import org.apache.derby.impl.jdbc.TransactionResourceImpl;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.jdbc.EngineConnection;import org.apache.derby.iapi.jdbc.ResourceAdapter;import org.apache.derby.iapi.jdbc.BrokeredConnection;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.services.context.ContextService;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.reference.JDBC30Translation;import org.apache.derby.iapi.services.info.JVMInfo;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;import java.sql.PreparedStatement;import java.sql.CallableStatement;/* import jta packages */import javax.transaction.xa.Xid;import javax.transaction.xa.XAResource;import javax.transaction.xa.XAException;/** -- jdbc 2.0. extension -- */import javax.sql.XAConnection;/** */final class EmbedXAConnection extends EmbedPooledConnection implements XAConnection, XAResource{ final ResourceAdapter ra; XAXactId currentXid; EmbedXAConnection(EmbeddedDataSource ds, ResourceAdapter ra, String u, String p, boolean requestPassword) throws SQLException { super(ds, u, p, requestPassword); this.ra = ra; } /* ** XAConnection methods */ public final synchronized XAResource getXAResource() throws SQLException { checkActive(); return this; } /* ** XAResource methods */ /** Start work on behalf of a transaction branch specified in xid If TMJOIN is specified, the start is for joining a transaction previously seen by the resource manager. If TMRESUME is specified, the start is to resume a suspended transaction specified in the parameter xid. If neither TMJOIN nor TMRESUME is specified and the transaction specified by xid has previously been seen by the resource manager, the resource manager throws the XAException exception with XAER_DUPID error code. @param xid A global transaction identifier to be associated with the resource @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME @exception XAException An error has occurred. Possible exceptions are XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA, XAER_INVAL, or XAER_PROTO. */ public final synchronized void start(Xid xid, int flags) throws XAException { checkXAActive(); // JDBC 3.0 section 12.3 - One transaction associated with a XAConnection if (currentXid != null) throw new XAException(XAException.XAER_PROTO); // ensure immtable and correct equals method. XAXactId xid_im = new XAXactId(xid); XATransactionState tranState = getTransactionState(xid_im); switch (flags) { case XAResource.TMNOFLAGS: if (tranState != null) throw new XAException(XAException.XAER_DUPID); try { if (realConnection == null) { openRealConnection(); if (currentConnectionHandle != null) { // since this is a new connection, set its complete // state according to the application's Connection // handle view of the world. currentConnectionHandle.setState(true); realConnection.setApplicationConnection(currentConnectionHandle); } } else { // XAResource.start() auto commits in DB2 when in auto commit mode. if (currentConnectionHandle != null) { if (currentConnectionHandle.getAutoCommit()) currentConnectionHandle.rollback(); } if (!realConnection.transactionIsIdle()) throw new XAException(XAException.XAER_OUTSIDE); if (currentConnectionHandle != null) { // It is possible that the isolation level state in connection // handle has gotten out of sync with the real isolation level. // This can happen if SLQ instead of JDBC api has been used to // set the isolation level. The code below will check if isolation // was set using JDBC or SQL and if yes, then it will update the // isolation state in BrokeredConnection with EmbedConnection's // isolation level. currentConnectionHandle.getIsolationUptoDate(); // we have a current handle so we need to keep // the connection state of the current connection. currentConnectionHandle.setState(true); // At the local to global transition we need to discard // and close any open held result sets, a rollback will do this. realConnection.rollback(); } else { resetRealConnection(); } } // Global connections are always in auto commit false mode. realConnection.setAutoCommit(false); // and holdability false (cannot hold cursors across XA transactions. realConnection.setHoldability(JDBC30Translation.CLOSE_CURSORS_AT_COMMIT); realConnection.getLanguageConnection(). getTransactionExecute().createXATransactionFromLocalTransaction( xid_im.getFormatId(), xid_im.getGlobalTransactionId(), xid_im.getBranchQualifier()); } catch (StandardException se) { throw wrapInXAException(se); } catch (SQLException sqle) { throw wrapInXAException(sqle); } if (!ra.addConnection(xid_im, new XATransactionState(realConnection.getContextManager(), realConnection, this, xid_im))) throw new XAException(XAException.XAER_DUPID); break; case XAResource.TMRESUME: case XAResource.TMJOIN: if (tranState == null) throw new XAException(XAException.XAER_NOTA); tranState.start(this, flags); if (tranState.conn != realConnection) { if (realConnection != null) { if (!realConnection.transactionIsIdle()) throw new XAException(XAException.XAER_OUTSIDE); // We need to get the isolation level up to date same // way as it is done at start of a transaction. Before // joining the transaction, it is possible that the // isolation level was updated using SQL. We need to // get this state and store in the connection handle so // that we can restore the isolation when we are in the // local mode. try { if (currentConnectionHandle != null) { currentConnectionHandle.getIsolationUptoDate(); } } catch (SQLException sqle) { throw wrapInXAException(sqle); } closeUnusedConnection(realConnection); } realConnection = tranState.conn; if (currentConnectionHandle != null) { try { // only reset the non-transaction specific Connection state. currentConnectionHandle.setState(false); realConnection.setApplicationConnection(currentConnectionHandle); } catch (SQLException sqle) { throw wrapInXAException(sqle); } } } break; default: throw new XAException(XAException.XAER_INVAL); } currentXid = xid_im; } /** Ends the work performed on behalf of a transaction branch. The resource manager disassociates the XA resource from the transaction branch specified and let the transaction be completed. <p> If TMSUSPEND is specified in flags, the transaction branch is temporarily suspended in incomplete state. The transaction context is in suspened state and must be resumed via start with TMRESUME specified. <p> If TMFAIL is specified, the portion of work has failed. The resource manager may mark the transaction as rollback-only <p> If TMSUCCESS is specified, the portion of work has completed successfully. @param xid A global transaction identifier that is the same as what was used previously in the start method. @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND @exception XAException An error has occurred. Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA, XAER_INVAL, XAER_PROTO, or XA_RB*. */ public final synchronized void end(Xid xid, int flags) throws XAException { checkXAActive(); try { // It is possible that the isolation level state in connection // handle has gotten out of sync with the real isolation level. // This can happen if SLQ instead of JDBC api has been used to // set the isolation level. The code below will check if isolation // was set using JDBC or SQL and if yes, then it will update the // isolation state in BrokeredConnection with EmbedConnection's // isolation level. if (currentConnectionHandle != null) currentConnectionHandle.getIsolationUptoDate(); } catch (SQLException sqle) { throw wrapInXAException(sqle); } // ensure immtable and correct equals method. XAXactId xid_im = new XAXactId(xid); boolean endingCurrentXid = false; // must match the Xid from start() if (currentXid != null) { if (!currentXid.equals(xid_im)) throw new XAException(XAException.XAER_PROTO); endingCurrentXid = true; } XATransactionState tranState = getTransactionState(xid_im); if (tranState == null) throw new XAException(XAException.XAER_NOTA); boolean rollbackOnly = tranState.end(this, flags, endingCurrentXid); // RESOLVE - what happens to the connection on a fail // where we are not ending the current XID. if (endingCurrentXid) { currentXid = null; realConnection = null; } if (rollbackOnly) throw new XAException(tranState.rollbackOnlyCode); } /** Ask the resource manager to prepare for a transaction commit of the transaction specified in xid. @param xid A global transaction identifier @return A value indicating the resource manager's vote on the outcome of the transaction. The possible values are: XA_RDONLY or XA_OK. If the resource manager wants to roll back the transaction, it should do so by raising an appropriate XAException in the prepare method. @exception XAException An error has occurred. Possible exception values are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. */ public final synchronized int prepare(Xid xid) throws XAException { checkXAActive(); // ensure immtable and correct equals method. XAXactId xid_im = new XAXactId(xid); XATransactionState tranState = getTransactionState(xid_im); if (tranState == null) { XAResourceManager rm = ra.getXAResourceManager(); ContextManager inDoubtCM = rm.find(xid); // RM also does not know about this xid. if (inDoubtCM == null) throw new XAException(XAException.XAER_NOTA); // cannot prepare in doubt transactions throw new XAException(XAException.XAER_PROTO); } synchronized (tranState) { checkUserCredentials(tranState.creatingResource); // Check the transaction is no associated with // any XAResource. switch (tranState.associationState) { case XATransactionState.T0_NOT_ASSOCIATED: break; case XATransactionState.TRO_FAIL: throw new XAException(tranState.rollbackOnlyCode); default: throw new XAException(XAException.XAER_PROTO); } if (tranState.suspendedList != null && tranState.suspendedList.size() != 0) throw new XAException(XAException.XAER_PROTO); if (tranState.isPrepared) throw new XAException(XAException.XAER_PROTO); EmbedConnection conn = tranState.conn; try { int ret = conn.xa_prepare(); if (ret == XATransactionController.XA_OK) { tranState.isPrepared = true; return XAResource.XA_OK; } else { returnConnectionToResource(tranState, xid_im); return XAResource.XA_RDONLY; } } catch (SQLException sqle) { throw wrapInXAException(sqle); } } } /** Commit the global transaction specified by xid. @param xid A global transaction identifier @param onePhase If true, the resource manager should use a one-phase commit protocol to commit the work done on behalf of xid. @exception XAException An error has occurred. Possible XAExceptions are XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. <P>If the resource manager did not commit the transaction and the paramether onePhase is set to true, the resource manager may throw one of the XA_RB* exceptions. Upon return, the resource manager has rolled back the branch's work and has released all held resources. */ public final synchronized void commit(Xid xid, boolean onePhase) throws XAException { checkXAActive(); // ensure immtable and correct equals method. XAXactId xid_im = new XAXactId(xid); XATransactionState tranState = getTransactionState(xid_im); if (tranState == null) { XAResourceManager rm = ra.getXAResourceManager(); ContextManager inDoubtCM = rm.find(xid); // RM also does not know about this xid. if (inDoubtCM == null) throw new XAException(XAException.XAER_NOTA); ContextService csf = ContextService.getFactory(); csf.setCurrentContextManager(inDoubtCM); try { rm.commit(inDoubtCM, xid_im, onePhase); // close the connection/transaction since it can never be used again. inDoubtCM.cleanupOnError(StandardException.closeException()); return; } catch (StandardException se) { // The rm threw an exception, clean it up in the approprate // context. There is no transactionResource to handle the // exception for us. inDoubtCM.cleanupOnError(se); throw wrapInXAException(se); } finally { csf.resetCurrentContextManager(inDoubtCM); } } synchronized (tranState) { checkUserCredentials(tranState.creatingResource); // Check the transaction is no associated with // any XAResource. switch (tranState.associationState) { case XATransactionState.T0_NOT_ASSOCIATED: break; case XATransactionState.TRO_FAIL: throw new XAException(tranState.rollbackOnlyCode); default: throw new XAException(XAException.XAER_PROTO); } if (tranState.suspendedList != null && tranState.suspendedList.size() != 0) throw new XAException(XAException.XAER_PROTO); if (tranState.isPrepared == onePhase) throw new XAException(XAException.XAER_PROTO); EmbedConnection conn = tranState.conn; try { conn.xa_commit(onePhase); } catch (SQLException sqle) { throw wrapInXAException(sqle); } finally { returnConnectionToResource(tranState, xid_im); } } } /** Inform the resource manager to roll back work done on behalf of a transaction branch @param xid A global transaction identifier @exception XAException - An error has occurred
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -