⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xaconnectionimpl.java

📁 SearchPathServer
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
			_txConn.conn = _underlying;
			_underlying = null;
		    } else
			_txConn.conn = _resManager.newConnection(_userName, _password);
		    _txConn.xid = xid;
		    _txConn.count = 1;
		    _txConn.started = System.currentTimeMillis();
		    _txConn.timeout = _txConn.started + ( _resManager.getTransactionTimeout() * 1000 );
		    _resManager.setTxConnection( xid, _txConn );
		} catch ( SQLException except ) {
		    // If error occured at this point, we can only
		    // report it as resource manager error.
		    if ( _resManager.getLogWriter() != null )
			_resManager.getLogWriter().println( "XAConnection: failed to begin a transaction: " + except );
		    throw new XAException( XAException.XAER_RMERR );
		}

		try {
		    _txConn.conn.setAutoCommit( false );
		    try {
			if ( _resManager.isolationLevel() != Connection.TRANSACTION_NONE )
			    _txConn.conn.setTransactionIsolation( _resManager.isolationLevel() );
		    } catch ( SQLException e ) {
			// The underlying driver might not support this
			// isolation level that we use by default.
		    }
		    if ( _txConn.conn instanceof TwoPhaseConnection )
			( (TwoPhaseConnection) _txConn.conn ).enableSQLTransactions( false );
		} catch ( SQLException except ) {
		    // If error occured at this point, we can only
		    // report it as resource manager error.
		    if ( _resManager.getLogWriter() != null )
			_resManager.getLogWriter().println( "XAConnection: failed to begin a transaction: " + except );
		    throw new XAException( XAException.XAER_RMERR );
		}
	    } else if ( flags == TMJOIN || flags == TMRESUME ) {
		// We are joining another transaction with an
		// existing TxConnection.
		_txConn = _resManager.getTxConnection( xid );
		if ( _txConn == null )
		    throw new XAException( XAException.XAER_INVAL );

		// Update the number of XAConnections sharing this
		// transaction connection.
		if ( flags == TMJOIN && _txConn.count == 0 )
		    throw new XAException( XAException.XAER_PROTO );
		++_txConn.count;

		// If we already have an underlying connection (as we can
		// expect to), we should release that underlying connection
		// and make it available to the resource manager.
		if ( _underlying != null ) {
		    releaseConnection( _underlying );
		    _underlying = null;
		}
	    } else
		// No other flags supported in start().
		throw new XAException( XAException.XAER_INVAL );
	}
    }


    public synchronized void end( Xid xid, int flags )
        throws XAException
    {
	// General checks.
	if ( xid == null )
	    throw new XAException( XAException.XAER_INVAL );
	// Note: we could get end with success or failure even it
	// we were previously excluded from the transaction.
	if ( _txConn == null && flags == TMSUSPEND ) 
	    throw new XAException( XAException.XAER_NOTA );

	synchronized ( _resManager ) {
	    if ( flags == TMSUCCESS || flags == TMFAIL) {
		// We are now leaving a transaction we started or
		// joined before. We can expect any of prepare/
		// commit/rollback to be called next, so TxConnection
		// is still valid.

		// If we were suspended from the transaction, we'll
		// join it for the duration of this operation.
		// Make sure the reference count reaches zero by the
		// time we get to prepare.
		if ( _txConn == null ) {
		    _txConn = _resManager.getTxConnection( xid );
		    if ( _txConn == null )
			throw new XAException( XAException.XAER_NOTA );
		} else {
		    if ( _txConn.xid != null && ! _txConn.xid.equals( xid ) )
			throw new XAException( XAException.XAER_NOTA );
		    --_txConn.count;
		}

		// If transaction failed, we can rollback the
		// transaction and release the underlying connection.
		// We can expect all other resources to recieved the
		// same end notification. We don't expect forget to happen.
		if ( flags == TMFAIL && _txConn.conn != null ) {
		    try {
			if ( _txConn.conn instanceof TwoPhaseConnection )
			    ( (TwoPhaseConnection) _txConn.conn ).enableSQLTransactions( true );
			_txConn.conn.rollback();
			releaseConnection( _txConn.conn );
		    } catch ( SQLException except ) {
			// There is a problem with the underlying
			// connection, but it was not added to the poll.
		    }
		    _resManager.setTxConnection( _txConn.xid, null );
		    _txConn.conn = null;
		    _txConn.xid = null;
		}

		if ( flags == TMSUCCESS) {
		    // We should be looking for a new transaction.
		    // Next thing we might be participating in a new
		    // transaction while the current one is being
		    // rolled back.
		    _txConn = null;
		}
	    } else if ( flags == TMSUSPEND ) {
		// We no longer take part in this transaction.
		// Possibly we'll be asked to resume later on, but
		// right now we have to forget about the transaction
		// and the underlying connection.
		--_txConn.count;
		_txConn = null;
	    } else
		// No other flags supported in end().
		throw new XAException( XAException.XAER_INVAL );
	}
    }


    public synchronized void forget( Xid xid )
	throws XAException
    {
	TxConnection txConn;

	// General checks.
	if ( xid == null )
	    throw new XAException( XAException.XAER_INVAL );
	synchronized ( _resManager ) {
	    // We have to forget about the transaction, meaning the
	    // transaction no longer exists for this or any other
	    // connection. We might be called multiple times.
	    txConn = _resManager.setTxConnection( xid, null );
	    if ( _txConn == txConn )
		_txConn = null;
	    if ( txConn != null ) {
		if ( txConn.conn != null ) {
		    releaseConnection( txConn.conn );
		    txConn.conn = null;
		}
		txConn.xid = null;
	    }
	}
    }


    public synchronized int prepare( Xid xid )
	throws XAException
    {
	TxConnection txConn;

	// General checks.
	if ( xid == null )
	    throw new XAException( XAException.XAER_INVAL );

	synchronized ( _resManager ) {
	    // Technically, prepare may be called for any connection,
	    // not just this one.
	    txConn = _resManager.getTxConnection( xid );
	    if ( txConn == null )
		throw new XAException( XAException.XAER_NOTA );

	    // This is an error and should never happen. All other
	    // parties in the transaction should have left it before.
	    if ( txConn.count > 0 )
		throw new XAException( XAException.XAER_PROTO );

	    // If the transaction failed, we have to force a rollback.
	    // We track the case of failure due to a timeout.
	    if ( txConn.timedOut )
		throw new XAException( XAException.XA_RBTIMEOUT );
	    if ( txConn.conn == null )
		throw new XAException( XAException.XA_RBROLLBACK );

	    // Since there is no preparation mechanism in a generic
	    // JDBC driver, we only test for read-only transaction
	    // but do not commit at this point.
	    try {
		txConn.prepared = true;
		if ( txConn.conn instanceof TwoPhaseConnection ) {
		    // For 2pc connection we ask it to prepare and determine
		    // whether it's commiting or read-only. If a rollback
		    // exception happens, we report it.
		    try {
			if ( ( (TwoPhaseConnection) txConn.conn ).prepare() )
			    return XA_OK;
			else {
			    txConn.readOnly = true;
			    return XA_RDONLY;
			}
		    } catch ( SQLException except ) {
			throw new XAException( XAException.XA_RBROLLBACK );
		    }
		} else {
		    // For standard connection we cannot prepare, we can
		    // only guess if it's read only.
		    if ( txConn.conn.isReadOnly() ) {
			txConn.readOnly = true;
			return XA_RDONLY;
		    }
		    return XA_OK;
		}
	    } catch ( SQLException except ) {
		try {
		    // Fatal error in the connection, kill it.
		    txConn.conn.close();
		} catch ( SQLException e ) { }
		txConn.conn = null;
		if ( _resManager.getLogWriter() != null )
		    _resManager.getLogWriter().println( "XAConnection: failed to commit a transaction: " + except );
		// If we cannot commit the transaction, force a rollback.
		throw new XAException( XAException.XA_RBROLLBACK );
	    }
	}
    }


    public Xid[] recover( int flags )
        throws XAException
    {
	synchronized ( _resManager ) {
	    return _resManager.getTxRecover();
	}
    }


    public synchronized void commit( Xid xid, boolean onePhase )
        throws XAException
    {
	TxConnection txConn;

	// General checks.
	if ( xid == null )
	    throw new XAException( XAException.XAER_INVAL );

	synchronized ( _resManager ) {
	    // Technically, commit may be called for any connection,
	    // not just this one.
	    txConn = _resManager.getTxConnection( xid );
	    if ( txConn == null )
		throw new XAException( XAException.XAER_NOTA );

	    // If the transaction failed, we have to force
	    // a rollback.
	    if ( txConn.conn == null )
		throw new XAException( XAException.XA_RBROLLBACK );

	    // If connection has been prepared and is read-only,
	    // nothing to do at this stage.
	    if ( txConn.readOnly )
		return;

	    // This must be a one-phase commite, or the connection
	    // should have been prepared before.
	    if ( onePhase || txConn.prepared ) {
		try {
		    // Prevent multiple commit attempts.
		    txConn.readOnly = true;
		    if ( txConn.conn instanceof TwoPhaseConnection )
			( (TwoPhaseConnection) txConn.conn ).enableSQLTransactions( true );
		    txConn.conn.commit();
		} catch ( SQLException except ) {
		    try {
			// Unknown error in the connection, better kill it.
			txConn.conn.close();
		    } catch ( SQLException e ) { }
		    txConn.conn = null;
		    if ( _resManager.getLogWriter() != null )
			_resManager.getLogWriter().println( "XAConnection: failed to commit a transaction: " + except );
		    // If we cannot commit the transaction, a heuristic tollback.
		    throw new XAException( XAException.XA_HEURRB );
		}
	    } else {
		// 2pc we should have prepared before.
		if ( ! txConn.prepared )
		    throw new XAException( XAException.XAER_PROTO );
	    }
	}
    }


    public synchronized void rollback( Xid xid )
        throws XAException
    {
	TxConnection txConn;


	// General checks.
	if ( xid == null )
	    throw new XAException( XAException.XAER_INVAL );

	synchronized ( _resManager ) {
	    // Technically, rollback may be called for any connection,
	    // not just this one.
	    txConn = _resManager.getTxConnection( xid );
	    if ( txConn == null )
		throw new XAException( XAException.XAER_NOTA );

	    // If connection has been prepared and is read-only,
	    // nothing to do at this stage. If connection has
	    // been terminated any other way, nothing to do
	    // either.
	    if ( txConn.readOnly || txConn.conn == null  )
		return;

	    try {
		txConn.prepared = false;
		if ( txConn.conn instanceof TwoPhaseConnection )
		    ( (TwoPhaseConnection) txConn.conn ).enableSQLTransactions( true );
		txConn.conn.rollback();
	    } catch ( SQLException except ) {
		try {
		    // Unknown error in the connection, better kill it.
		    txConn.conn.close();
		} catch ( SQLException e ) { }
		txConn.conn = null;
		if ( _resManager.getLogWriter() != null )
		    _resManager.getLogWriter().println( "XAConnection: failed to rollback a transaction: " + except );
		// If we cannot commit the transaction, a heuristic tollback.
		throw new XAException( XAException.XA_RBROLLBACK );
	    } finally {
		forget( xid );
	    }
	}
    }


    public synchronized boolean isSameRM( XAResource xaRes )
	throws XAException
    {
	// Two resource managers are equal if they produce equivalent
	// connection (i.e. same database, same user). If the two are
	// equivalent they would share a transaction by joining.
	if ( xaRes == null || ! ( xaRes instanceof XAConnectionImpl ) )
	    return false;
	if ( _resManager.equals( ( (XAConnectionImpl) xaRes )._resManager ) )
	    return true;
	return false;
    }


    public synchronized boolean setTransactionTimeout( int seconds )
	throws XAException
    {
	if ( seconds < 0 )
	    throw new XAException( XAException.XAER_INVAL );
	// Zero resets to the default for all transactions.
	if ( seconds == 0 )
	    seconds = _resManager.getTransactionTimeout();
	// If a transaction has started, change it's timeout to the new value.
	if ( _txConn != null ) {
	    _txConn.timeout = _txConn.started + ( seconds * 1000 );
	    return true;
	}
	return false;
    }


    public int getTransactionTimeout()
    {
	long timeout;

	if ( _txConn == null )
	    return 0;
	return (int) ( _txConn.timeout - _txConn.started ) / 1000;
    }


    /**
     * Returns true if this connection is inside a global transaction.
     * If the connection is inside a global transaction it will not
     * allow commit/rollback directly from the {@link
     * java.sql.Connection} interface.
     */
    boolean insideGlobalTx()
    {
	return ( _txConn != null );
    }


    /**
     * Called to obtain the underlying connections. If this connection
     * is part of a transaction, the transction's underlying connection
     * is returned, or an exception is thrown if the connection was
     * terminated due to timeout. If this connection is not part of a
     * transaction, a non-transactional connection is returned.
     *
     * @param clientId The {@link ClientConnection} identifier
     */
    Connection getUnderlying( int clientId )
	throws SQLException
    {
	// If we were notified of the client closing, or have been
	// requested to have a new client connection since then,
	// the client id will not match to that of the caller.
	// We use that to decide that the caller has been closed.
	if ( clientId != _clientId )
	    throw new SQLException( "This application connection has been closed" );

	if ( _txConn != null ) {
	    if ( _txConn.timedOut )
		throw new SQLException( "The transaction has timed out and has been rolledback and closed" );
	    if ( _txConn.conn == null )
		throw new SQLException( "The transaction has been terminated and this connection has been closed" );
	    return _txConn.conn;
	}
	if ( _underlying == null ) {
	    _underlying = _resManager.newConnection(_userName, _password);
	    _underlying.setAutoCommit( true );
	}
	return _underlying;
    }

    /**
     * Release the specified connection to the resource manager
     *
     * @param connection the connection to release
     */
    private void releaseConnection( Connection connection )
    {
        _resManager.releaseConnection( connection, _userName, _password );
    }

}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -