mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
去掉还没实现的xa部分代码
git-svn-id: http://code.alibabatech.com/svn/druid/trunk@349 b9813039-fb51-4c41-a8b9-e21c2acb5095
This commit is contained in:
@@ -147,12 +147,6 @@
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jta</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
<version>1.0.1b</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import javax.sql.XAConnection;
|
||||
import javax.sql.XADataSource;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class DataSourceXAConnectionFactory implements XAConnectionFactory {
|
||||
|
||||
protected TransactionRegistry transactionRegistry;
|
||||
protected XADataSource xaDataSource;
|
||||
protected String username;
|
||||
protected String password;
|
||||
|
||||
/**
|
||||
* Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
|
||||
* The connections are enlisted into transactions using the specified transaction manager.
|
||||
*
|
||||
* @param transactionManager the transaction manager in which connections will be enlisted
|
||||
* @param xaDataSource the data source from which connections will be retrieved
|
||||
*/
|
||||
public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource){
|
||||
this(transactionManager, xaDataSource, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
|
||||
* The connections are enlisted into transactions using the specified transaction manager.
|
||||
*
|
||||
* @param transactionManager the transaction manager in which connections will be enlisted
|
||||
* @param xaDataSource the data source from which connections will be retrieved
|
||||
* @param username the username used for authenticating new connections or null for unauthenticated
|
||||
* @param password the password used for authenticating new connections
|
||||
*/
|
||||
public DataSourceXAConnectionFactory(TransactionManager transactionManager, XADataSource xaDataSource, String username, String password){
|
||||
if (transactionManager == null) throw new NullPointerException("transactionManager is null");
|
||||
if (xaDataSource == null) throw new NullPointerException("xaDataSource is null");
|
||||
|
||||
this.transactionRegistry = new TransactionRegistry(transactionManager);
|
||||
this.xaDataSource = xaDataSource;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username used to authenticate new connections.
|
||||
*
|
||||
* @return the user name or null if unauthenticated connections are used
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username used to authenticate new connections.
|
||||
*
|
||||
* @param username the username used for authenticating the connection or null for unauthenticated
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password used to authenticate new connections.
|
||||
*
|
||||
* @param password the password used for authenticating the connection or null for unauthenticated
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public TransactionRegistry getTransactionRegistry() {
|
||||
return transactionRegistry;
|
||||
}
|
||||
|
||||
public Connection createConnection() throws SQLException {
|
||||
// create a new XAConection
|
||||
XAConnection xaConnection;
|
||||
if (username == null) {
|
||||
xaConnection = xaDataSource.getXAConnection();
|
||||
} else {
|
||||
xaConnection = xaDataSource.getXAConnection(username, password);
|
||||
}
|
||||
|
||||
// get the real connection and XAResource from the connection
|
||||
Connection connection = xaConnection.getConnection();
|
||||
XAResource xaResource = xaConnection.getXAResource();
|
||||
|
||||
// register the xa resource for the connection
|
||||
transactionRegistry.registerConnection(connection, xaResource);
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.XADataSource;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import com.alibaba.druid.pool.ConnectionFactory;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
public class DruidXADataSource extends DruidDataSource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Transaction Registry */
|
||||
private TransactionRegistry transactionRegistry;
|
||||
/** Transaction Manager */
|
||||
private transient TransactionManager transactionManager;
|
||||
/** XA datasource class name */
|
||||
private String xaDataSource;
|
||||
/** XA datasource instance */
|
||||
private XADataSource xaDataSourceInstance;
|
||||
|
||||
/**
|
||||
* Gets the XADataSource instance used by the XAConnectionFactory.
|
||||
*
|
||||
* @return the XADataSource
|
||||
*/
|
||||
public synchronized XADataSource getXaDataSourceInstance() {
|
||||
return xaDataSourceInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the XADataSource instance used by the XAConnectionFactory.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
|
||||
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
|
||||
* setLoginTimeout, getLoginTimeout, getLogWriter.</code>
|
||||
* </p>
|
||||
*
|
||||
* @param xaDataSourceInstance XADataSource instance
|
||||
*/
|
||||
public synchronized void setXaDataSourceInstance(XADataSource xaDataSourceInstance) {
|
||||
this.xaDataSourceInstance = xaDataSourceInstance;
|
||||
xaDataSource = xaDataSourceInstance == null ? null : xaDataSourceInstance.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required transaction manager property.
|
||||
*
|
||||
* @return the transaction manager used to enlist connections
|
||||
*/
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transaction registry.
|
||||
*
|
||||
* @return the transaction registry associating XAResources with managed connections
|
||||
*/
|
||||
protected synchronized TransactionRegistry getTransactionRegistry() {
|
||||
return transactionRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required transaction manager property.
|
||||
*
|
||||
* @param transactionManager the transaction manager used to enlist connections
|
||||
*/
|
||||
public void setTransactionManager(TransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional XADataSource class name.
|
||||
*
|
||||
* @return the optional XADataSource class name
|
||||
*/
|
||||
public synchronized String getXADataSource() {
|
||||
return xaDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional XADataSource class name.
|
||||
*
|
||||
* @param xaDataSource the optional XADataSource class name
|
||||
*/
|
||||
public synchronized void setXADataSource(String xaDataSource) {
|
||||
this.xaDataSource = xaDataSource;
|
||||
}
|
||||
|
||||
protected ConnectionFactory createConnectionFactory() throws SQLException {
|
||||
if (transactionManager == null) {
|
||||
throw new SQLException("Transaction manager must be set before a connection can be created");
|
||||
}
|
||||
|
||||
// If xa data source is not specified a DriverConnectionFactory is created and wrapped with a
|
||||
// LocalXAConnectionFactory
|
||||
if (xaDataSource == null) {
|
||||
ConnectionFactory connectionFactory = super.createConnectionFactory();
|
||||
XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory);
|
||||
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
|
||||
return xaConnectionFactory;
|
||||
}
|
||||
|
||||
// Create the XADataSource instance using the configured class name if it has not been set
|
||||
if (xaDataSourceInstance == null) {
|
||||
Class<?> xaDataSourceClass = null;
|
||||
try {
|
||||
xaDataSourceClass = Class.forName(xaDataSource);
|
||||
} catch (Throwable t) {
|
||||
String message = "Cannot load XA data source class '" + xaDataSource + "'";
|
||||
throw (SQLException) new SQLException(message).initCause(t);
|
||||
}
|
||||
|
||||
try {
|
||||
xaDataSourceInstance = (XADataSource) xaDataSourceClass.newInstance();
|
||||
} catch (Throwable t) {
|
||||
String message = "Cannot create XA data source of class '" + xaDataSource + "'";
|
||||
throw (SQLException) new SQLException(message).initCause(t);
|
||||
}
|
||||
}
|
||||
|
||||
// finally, create the XAConectionFactory using the XA data source
|
||||
XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, username, password);
|
||||
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
|
||||
return xaConnectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the PoolableConnectionFactory and attaches it to the connection pool.
|
||||
*
|
||||
* @param driverConnectionFactory JDBC connection factory created by {@link #createConnectionFactory()}
|
||||
* @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
|
||||
* @param abandonedConfig abandoned connection tracking configuration (null if no tracking)
|
||||
* @throws SQLException if an error occurs creating the PoolableConnectionFactory
|
||||
*/
|
||||
protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory) throws SQLException {
|
||||
// PoolableConnectionFactory connectionFactory = null;
|
||||
// try {
|
||||
// connectionFactory = new PoolableManagedConnectionFactory((XAConnectionFactory) driverConnectionFactory,
|
||||
// connectionPool, statementPoolFactory,
|
||||
// validationQuery, validationQueryTimeout,
|
||||
// connectionInitSqls, defaultReadOnly,
|
||||
// defaultAutoCommit, defaultTransactionIsolation,
|
||||
// defaultCatalog, abandonedConfig);
|
||||
// validateConnectionFactory(connectionFactory);
|
||||
// } catch (RuntimeException e) {
|
||||
// throw e;
|
||||
// } catch (Exception e) {
|
||||
// throw (SQLException) new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() +
|
||||
// ")").initCause(e);
|
||||
// }
|
||||
throw new SQLException("TODO");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAException;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
|
||||
import com.alibaba.druid.pool.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* An implementation of XAConnectionFactory which manages non-XA connections in XA transactions. A non-XA connection
|
||||
* commits and rolls back as part of the XA transaction, but is not recoverable since the connection does not implement
|
||||
* the 2-phase protocol.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class LocalXAConnectionFactory implements XAConnectionFactory {
|
||||
|
||||
protected TransactionRegistry transactionRegistry;
|
||||
protected ConnectionFactory connectionFactory;
|
||||
|
||||
/**
|
||||
* Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections.
|
||||
* The connections are enlisted into transactions using the specified transaction manager.
|
||||
*
|
||||
* @param transactionManager the transaction manager in which connections will be enlisted
|
||||
* @param connectionFactory the connection factory from which connections will be retrieved
|
||||
*/
|
||||
public LocalXAConnectionFactory(TransactionManager transactionManager, ConnectionFactory connectionFactory){
|
||||
if (transactionManager == null) {
|
||||
throw new NullPointerException("transactionManager is null");
|
||||
}
|
||||
|
||||
if (connectionFactory == null) {
|
||||
throw new NullPointerException("connectionFactory is null");
|
||||
}
|
||||
|
||||
this.transactionRegistry = new TransactionRegistry(transactionManager);
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public TransactionRegistry getTransactionRegistry() {
|
||||
return transactionRegistry;
|
||||
}
|
||||
|
||||
public Connection createConnection() throws SQLException {
|
||||
// create a new connection
|
||||
Connection connection = connectionFactory.createConnection();
|
||||
|
||||
// create a XAResource to manage the connection during XA transactions
|
||||
XAResource xaResource = new LocalXAResource(connection);
|
||||
|
||||
// register the xa resource for the connection
|
||||
transactionRegistry.registerConnection(connection, xaResource);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalXAResource is a fake XAResource for non-XA connections. When a transaction is started the connection
|
||||
* auto-commit is turned off. When the connection is committed or rolled back, the commit or rollback method is
|
||||
* called on the connection and then the original auto-commit value is restored. </p> The LocalXAResource also
|
||||
* respects the connection read-only setting. If the connection is read-only the commit method will not be called,
|
||||
* and the prepare method returns the XA_RDONLY. </p> It is assumed that the wrapper around a managed connection
|
||||
* disables the setAutoCommit(), commit(), rollback() and setReadOnly() methods while a transaction is in progress.
|
||||
*/
|
||||
protected static class LocalXAResource implements XAResource {
|
||||
|
||||
private final Connection connection;
|
||||
private Xid currentXid;
|
||||
private boolean originalAutoCommit;
|
||||
|
||||
public LocalXAResource(Connection localTransaction){
|
||||
this.connection = localTransaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current xid of the transaction branch associated with this XAResource.
|
||||
*
|
||||
* @return the current xid of the transaction branch associated with this XAResource.
|
||||
*/
|
||||
public synchronized Xid getXid() {
|
||||
return currentXid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a the connection has been enrolled in a transaction. This method saves off the current auto
|
||||
* commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction
|
||||
* completes.
|
||||
*
|
||||
* @param xid the id of the transaction branch for this connection
|
||||
* @param flag either XAResource.TMNOFLAGS or XAResource.TMRESUME
|
||||
* @throws XAException if the connection is already enlisted in another transaction, or if auto-commit could not
|
||||
* be disabled
|
||||
*/
|
||||
public synchronized void start(Xid xid, int flag) throws XAException {
|
||||
if (flag == XAResource.TMNOFLAGS) {
|
||||
// first time in this transaction
|
||||
|
||||
// make sure we aren't already in another tx
|
||||
if (this.currentXid != null) {
|
||||
throw new XAException("Already enlisted in another transaction with xid " + xid);
|
||||
}
|
||||
|
||||
// save off the current auto commit flag so it can be restored after the transaction completes
|
||||
try {
|
||||
originalAutoCommit = connection.getAutoCommit();
|
||||
} catch (SQLException ignored) {
|
||||
// no big deal, just assume it was off
|
||||
originalAutoCommit = true;
|
||||
}
|
||||
|
||||
// update the auto commit flag
|
||||
try {
|
||||
connection.setAutoCommit(false);
|
||||
} catch (SQLException e) {
|
||||
throw (XAException) new XAException("Count not turn off auto commit for a XA transaction").initCause(e);
|
||||
}
|
||||
|
||||
this.currentXid = xid;
|
||||
} else if (flag == XAResource.TMRESUME) {
|
||||
if (xid != this.currentXid) {
|
||||
throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid + ", but was " + xid);
|
||||
}
|
||||
} else {
|
||||
throw new XAException("Unknown start flag " + flag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does nothing.
|
||||
*
|
||||
* @param xid the id of the transaction branch for this connection
|
||||
* @param flag ignored
|
||||
* @throws XAException if the connection is already enlisted in another transaction
|
||||
*/
|
||||
public synchronized void end(Xid xid, int flag) throws XAException {
|
||||
if (xid == null) throw new NullPointerException("xid is null");
|
||||
if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
|
||||
|
||||
// This notification tells us that the application server is done using this
|
||||
// connection for the time being. The connection is still associated with an
|
||||
// open transaction, so we must still wait for the commit or rollback method
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does nothing since the LocalXAConnection does not support two-phase-commit. This method will
|
||||
* return XAResource.XA_RDONLY if the connection isReadOnly(). This assumes that the physical connection is
|
||||
* wrapped with a proxy that prevents an application from changing the read-only flag while enrolled in a
|
||||
* transaction.
|
||||
*
|
||||
* @param xid the id of the transaction branch for this connection
|
||||
* @return XAResource.XA_RDONLY if the connection.isReadOnly(); XAResource.XA_OK otherwise
|
||||
*/
|
||||
public synchronized int prepare(Xid xid) {
|
||||
// if the connection is read-only, then the resource is read-only
|
||||
// NOTE: this assumes that the outer proxy throws an exception when application code
|
||||
// attempts to set this in a transaction
|
||||
try {
|
||||
if (connection.isReadOnly()) {
|
||||
// update the auto commit flag
|
||||
connection.setAutoCommit(originalAutoCommit);
|
||||
|
||||
// tell the transaction manager we are read only
|
||||
return XAResource.XA_RDONLY;
|
||||
}
|
||||
} catch (SQLException ignored) {
|
||||
// no big deal
|
||||
}
|
||||
|
||||
// this is a local (one phase) only connection, so we can't prepare
|
||||
return XAResource.XA_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the transaction and restores the original auto commit setting.
|
||||
*
|
||||
* @param xid the id of the transaction branch for this connection
|
||||
* @param flag ignored
|
||||
* @throws XAException if connection.commit() throws a SQLException
|
||||
*/
|
||||
public synchronized void commit(Xid xid, boolean flag) throws XAException {
|
||||
if (xid == null) throw new NullPointerException("xid is null");
|
||||
if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
|
||||
|
||||
try {
|
||||
// make sure the connection isn't already closed
|
||||
if (connection.isClosed()) {
|
||||
throw new XAException("Conection is closed");
|
||||
}
|
||||
|
||||
// A read only connection should not be committed
|
||||
if (!connection.isReadOnly()) {
|
||||
connection.commit();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw (XAException) new XAException().initCause(e);
|
||||
} finally {
|
||||
try {
|
||||
connection.setAutoCommit(originalAutoCommit);
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
this.currentXid = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rolls back the transaction and restores the original auto commit setting.
|
||||
*
|
||||
* @param xid the id of the transaction branch for this connection
|
||||
* @throws XAException if connection.rollback() throws a SQLException
|
||||
*/
|
||||
public synchronized void rollback(Xid xid) throws XAException {
|
||||
if (xid == null) throw new NullPointerException("xid is null");
|
||||
if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
|
||||
|
||||
try {
|
||||
connection.rollback();
|
||||
} catch (SQLException e) {
|
||||
throw (XAException) new XAException().initCause(e);
|
||||
} finally {
|
||||
try {
|
||||
connection.setAutoCommit(originalAutoCommit);
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
this.currentXid = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified XAResource == this XAResource.
|
||||
*
|
||||
* @param xaResource the XAResource to test
|
||||
* @return true if the specified XAResource == this XAResource; false otherwise
|
||||
*/
|
||||
public boolean isSameRM(XAResource xaResource) {
|
||||
return this == xaResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the currently associated transaction if it is the specified xid.
|
||||
*
|
||||
* @param xid the id of the transaction to forget
|
||||
*/
|
||||
public synchronized void forget(Xid xid) {
|
||||
if (xid != null && this.currentXid.equals(xid)) {
|
||||
this.currentXid = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids
|
||||
* will ever be found.
|
||||
*
|
||||
* @param flag ignored since recovery is not supported
|
||||
* @return always a zero length Xid array.
|
||||
*/
|
||||
public Xid[] recover(int flag) {
|
||||
return new Xid[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns 0 since we have no way to set a transaction timeout on a JDBC connection.
|
||||
*
|
||||
* @return always 0
|
||||
*/
|
||||
public int getTransactionTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns false since we have no way to set a transaction timeout on a JDBC connection.
|
||||
*
|
||||
* @param transactionTimeout ignored since we have no way to set a transaction timeout on a JDBC connection
|
||||
* @return always false
|
||||
*/
|
||||
public boolean setTransactionTimeout(int transactionTimeout) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.ConnectionHolder;
|
||||
import com.alibaba.druid.pool.PoolableConnection;
|
||||
|
||||
/**
|
||||
* ManagedConnection is responsible for managing a database connection in a transactional environment (typically called
|
||||
* "Container Managed"). A managed connection operates like any other connection when no global transaction (a.k.a. XA
|
||||
* transaction or JTA Transaction) is in progress. When a global transaction is active a single physical connection to
|
||||
* the database is used by all ManagedConnections accessed in the scope of the transaction. Connection sharing means
|
||||
* that all data access during a transaction has a consistent view of the database. When the global transaction is
|
||||
* committed or rolled back the enlisted connections are committed or rolled back. Typically upon transaction
|
||||
* completion, a connection returns to the auto commit setting in effect before being enlisted in the transaction, but
|
||||
* some vendors do not properly implement this. When enlisted in a transaction the setAutoCommit(), commit(),
|
||||
* rollback(), and setReadOnly() methods throw a SQLException. This is necessary to assure that the transaction
|
||||
* completes as a single unit.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ManagedConnection extends PoolableConnection {
|
||||
|
||||
private final TransactionRegistry transactionRegistry;
|
||||
private final boolean accessToUnderlyingConnectionAllowed;
|
||||
private TransactionContext transactionContext;
|
||||
private boolean isSharedConnection;
|
||||
|
||||
public ManagedConnection(ConnectionHolder holder, TransactionRegistry transactionRegistry, boolean accessToUnderlyingConnectionAllowed) throws SQLException{
|
||||
super(holder);
|
||||
this.transactionRegistry = transactionRegistry;
|
||||
this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
|
||||
updateTransactionStatus();
|
||||
}
|
||||
|
||||
protected void checkOpen() throws SQLException {
|
||||
super.checkOpen();
|
||||
updateTransactionStatus();
|
||||
}
|
||||
|
||||
private void updateTransactionStatus() throws SQLException {
|
||||
// // if there is a is an active transaction context, assure the transaction context hasn't changed
|
||||
// if (transactionContext != null) {
|
||||
// if (transactionContext.isActive()) {
|
||||
// if (transactionContext != transactionRegistry.getActiveTransactionContext()) {
|
||||
// throw new SQLException("Connection can not be used while enlisted in another transaction");
|
||||
// }
|
||||
// return;
|
||||
// } else {
|
||||
// // transaction should have been cleared up by TransactionContextListener, but in
|
||||
// // rare cases another lister could have registered which uses the connection before
|
||||
// // our listener is called. In that rare case, trigger the transaction complete call now
|
||||
// transactionComplete();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // the existing transaction context ended (or we didn't have one), get the active transaction context
|
||||
// transactionContext = transactionRegistry.getActiveTransactionContext();
|
||||
//
|
||||
// // if there is an active transaction context and it already has a shared connection, use it
|
||||
// if (transactionContext != null && transactionContext.getSharedConnection() != null) {
|
||||
// // A connection for the connection factory has already been enrolled
|
||||
// // in the transaction, replace our delegate with the enrolled connection
|
||||
//
|
||||
// // return current connection to the pool
|
||||
// Connection connection = getDelegateInternal();
|
||||
// setDelegate(null);
|
||||
// if (connection != null) {
|
||||
// try {
|
||||
// pool.returnObject(connection);
|
||||
// } catch (Exception ignored) {
|
||||
// // whatever... try to invalidate the connection
|
||||
// try {
|
||||
// pool.invalidateObject(connection);
|
||||
// } catch (Exception ignore) {
|
||||
// // no big deal
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // add a listener to the transaction context
|
||||
// transactionContext.addTransactionContextListener(new CompletionListener());
|
||||
//
|
||||
// // set our delegate to the shared connection
|
||||
// setDelegate(transactionContext.getSharedConnection());
|
||||
//
|
||||
// // remember that we are using a shared connection so it can be cleared after the
|
||||
// // transaction completes
|
||||
// isSharedConnection = true;
|
||||
// } else {
|
||||
// // if our delegate is null, create one
|
||||
// if (getDelegateInternal() == null) {
|
||||
// try {
|
||||
// // borrow a new connection from the pool
|
||||
// Connection connection = (Connection) pool.borrowObject();
|
||||
// setDelegate(connection);
|
||||
// } catch (Exception e) {
|
||||
// throw (SQLException) new SQLException("Unable to acquire a new connection from the pool").initCause(e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // if we have a transaction, out delegate becomes the shared delegate
|
||||
// if (transactionContext != null) {
|
||||
// // add a listener to the transaction context
|
||||
// transactionContext.addTransactionContextListener(new CompletionListener());
|
||||
//
|
||||
// // register our connection as the shared connection
|
||||
// try {
|
||||
// transactionContext.setSharedConnection(getDelegateInternal());
|
||||
// } catch (SQLException e) {
|
||||
// // transaction is hosed
|
||||
// transactionContext = null;
|
||||
// throw e;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
throw new SQLException("TODO");
|
||||
}
|
||||
|
||||
public void close() throws SQLException {
|
||||
if (transactionContext == null) {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events.
|
||||
*/
|
||||
protected class CompletionListener implements TransactionContextListener {
|
||||
|
||||
public void afterCompletion(TransactionContext completedContext, boolean commited) {
|
||||
if (completedContext == transactionContext) {
|
||||
transactionComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void transactionComplete() {
|
||||
// transactionContext = null;
|
||||
//
|
||||
// // if we were using a shared connection, clear the reference now that the transaction has completed
|
||||
// if (isSharedConnection) {
|
||||
// // for now, just set the delegate to null, it will be created later if needed
|
||||
// setDelegate(null);
|
||||
// isSharedConnection = false;
|
||||
// }
|
||||
//
|
||||
// // if this connection was closed during the transaction and there is still a delegate present close it
|
||||
// Connection delegate = getDelegateInternal();
|
||||
// if (isClosed() && delegate != null) {
|
||||
// try {
|
||||
// setDelegate(null);
|
||||
//
|
||||
// // don't actually close the connection if in a transaction
|
||||
// if (!delegate.isClosed()) {
|
||||
// // don't use super.close() because it calls passivate() which marks the
|
||||
// // the connection as closed without returning it to the pool
|
||||
// delegate.close();
|
||||
// }
|
||||
// } catch (SQLException ignored) {
|
||||
// // not a whole lot we can do here as connection is closed
|
||||
// // and this is a transaction callback so there is no
|
||||
// // way to report the error
|
||||
// } finally {
|
||||
// _closed = true;
|
||||
// }
|
||||
// }
|
||||
throw new RuntimeException("TODO");
|
||||
}
|
||||
|
||||
//
|
||||
// The following methods can't be used while enlisted in a transaction
|
||||
//
|
||||
|
||||
public void setAutoCommit(boolean autoCommit) throws SQLException {
|
||||
if (transactionContext != null) {
|
||||
throw new SQLException("Auto-commit can not be set while enrolled in a transaction");
|
||||
}
|
||||
super.setAutoCommit(autoCommit);
|
||||
}
|
||||
|
||||
public void commit() throws SQLException {
|
||||
if (transactionContext != null) {
|
||||
throw new SQLException("Commit can not be set while enrolled in a transaction");
|
||||
}
|
||||
super.commit();
|
||||
}
|
||||
|
||||
public void rollback() throws SQLException {
|
||||
if (transactionContext != null) {
|
||||
throw new SQLException("Commit can not be set while enrolled in a transaction");
|
||||
}
|
||||
super.rollback();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) throws SQLException {
|
||||
if (transactionContext != null) {
|
||||
throw new SQLException("Read-only can not be set while enrolled in a transaction");
|
||||
}
|
||||
super.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
//
|
||||
// Methods for accessing the delegate connection
|
||||
//
|
||||
|
||||
/**
|
||||
* If false, getDelegate() and getInnermostDelegate() will return null.
|
||||
*
|
||||
* @return if false, getDelegate() and getInnermostDelegate() will return null
|
||||
*/
|
||||
public boolean isAccessToUnderlyingConnectionAllowed() {
|
||||
return accessToUnderlyingConnectionAllowed;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Connection getDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return getRawConnection();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Connection getInnermostDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return getRawConnection();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The ManagedDataSource is a PoolingDataSource that creates ManagedConnections.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class ManagedDataSource {
|
||||
|
||||
private TransactionRegistry transactionRegistry;
|
||||
|
||||
/**
|
||||
* Creates an uninitialized datasource. Before this data source can be used a pool and transaction registry must be
|
||||
* set.
|
||||
*/
|
||||
public ManagedDataSource(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ManagedDataSource which obtains connections from the specified pool and manages them using the
|
||||
* specified transaction registry. The TransactionRegistry must be the transaction registry obtained from the
|
||||
* XAConnectionFactory used to create the connection pool. If not an error will occure when attempting to use the
|
||||
* connection in a global transaction because the XAResource object associated with the connection will be
|
||||
* unavailable.
|
||||
*
|
||||
* @param pool the connection pool
|
||||
* @param transactionRegistry the transaction registry obtained from the XAConnectionFactory used to create the
|
||||
* connection pool object factory
|
||||
*/
|
||||
public ManagedDataSource(TransactionRegistry transactionRegistry){
|
||||
this.transactionRegistry = transactionRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transaction registry from the XAConnectionFactory used to create the pool. The transaction registry can
|
||||
* only be set once using either a connector or this setter method.
|
||||
*
|
||||
* @param transactionRegistry the transaction registry acquired from the XAConnectionFactory used to create the pool
|
||||
*/
|
||||
public void setTransactionRegistry(TransactionRegistry transactionRegistry) {
|
||||
if (this.transactionRegistry != null) throw new IllegalStateException("TransactionRegistry already set");
|
||||
if (transactionRegistry == null) throw new NullPointerException("TransactionRegistry is null");
|
||||
|
||||
this.transactionRegistry = transactionRegistry;
|
||||
}
|
||||
|
||||
public Connection getConnection() throws SQLException {
|
||||
// if (_pool == null) throw new IllegalStateException("Pool has not been set");
|
||||
// if (transactionRegistry == null) throw new IllegalStateException("TransactionRegistry has not been set");
|
||||
//
|
||||
// Connection connection = new ManagedConnection(_pool, transactionRegistry,
|
||||
// isAccessToUnderlyingConnectionAllowed());
|
||||
// return connection;
|
||||
throw new SQLException("TODO"); // TODO
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* TransactionContext represents the association between a single XAConnectionFactory and a Transaction. This context
|
||||
* contains a single shared connection which should be used by all ManagedConnections for the XAConnectionFactory, the
|
||||
* ability to listen for the transaction completion event, and a method to check the status of the transaction.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class TransactionContext {
|
||||
|
||||
private final TransactionRegistry transactionRegistry;
|
||||
private final WeakReference<Transaction> transactionRef;
|
||||
private Connection sharedConnection;
|
||||
|
||||
/**
|
||||
* Creates a TransactionContext for the specified Transaction and TransactionRegistry. The TransactionRegistry is
|
||||
* used to obtain the XAResource for the shared connection when it is enlisted in the transaction.
|
||||
*
|
||||
* @param transactionRegistry the TransactionRegistry used to obtain the XAResource for the shared connection
|
||||
* @param transaction the transaction
|
||||
*/
|
||||
public TransactionContext(TransactionRegistry transactionRegistry, Transaction transaction){
|
||||
if (transactionRegistry == null) throw new NullPointerException("transactionRegistry is null");
|
||||
if (transaction == null) throw new NullPointerException("transaction is null");
|
||||
this.transactionRegistry = transactionRegistry;
|
||||
this.transactionRef = new WeakReference<Transaction>(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection shared by all ManagedConnections in the transaction. Specifically, connection using the same
|
||||
* XAConnectionFactory from which the TransactionRegistry was obtained.
|
||||
*
|
||||
* @return the shared connection for this transaction
|
||||
*/
|
||||
public Connection getSharedConnection() {
|
||||
return sharedConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shared connection for this transaction. The shared connection is enlisted in the transaction.
|
||||
*
|
||||
* @param sharedConnection the shared connection
|
||||
* @throws SQLException if a shared connection is already set, if XAResource for the connection could not be found
|
||||
* in the transaction registry, or if there was a problem enlisting the connection in the transaction
|
||||
*/
|
||||
public void setSharedConnection(Connection sharedConnection) throws SQLException {
|
||||
if (this.sharedConnection != null) {
|
||||
throw new IllegalStateException("A shared connection is alredy set");
|
||||
}
|
||||
|
||||
// This is the first use of the connection in this transaction, so we must
|
||||
// enlist it in the transaction
|
||||
Transaction transaction = getTransaction();
|
||||
try {
|
||||
XAResource xaResource = transactionRegistry.getXAResource(sharedConnection);
|
||||
transaction.enlistResource(xaResource);
|
||||
} catch (RollbackException e) {
|
||||
// transaction was rolled back... proceed as if there never was a transaction
|
||||
} catch (SystemException e) {
|
||||
throw (SQLException) new SQLException("Unable to enlist connection the transaction").initCause(e);
|
||||
}
|
||||
|
||||
this.sharedConnection = sharedConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for transaction completion events.
|
||||
*
|
||||
* @param listener the listener to add
|
||||
* @throws SQLException if a problem occurs adding the listener to the transaction
|
||||
*/
|
||||
public void addTransactionContextListener(final TransactionContextListener listener) throws SQLException {
|
||||
try {
|
||||
getTransaction().registerSynchronization(new Synchronization() {
|
||||
|
||||
public void beforeCompletion() {
|
||||
}
|
||||
|
||||
public void afterCompletion(int status) {
|
||||
listener.afterCompletion(TransactionContext.this, status == Status.STATUS_COMMITTED);
|
||||
}
|
||||
});
|
||||
} catch (RollbackException e) {
|
||||
// JTA spec doesn't let us register with a transaction marked rollback only
|
||||
// just ignore this and the tx state will be cleared another way.
|
||||
} catch (Exception e) {
|
||||
throw (SQLException) new SQLException("Unable to register transaction context listener").initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the transaction is active or marked for rollback only.
|
||||
*
|
||||
* @return true if the transaction is active or marked for rollback only; false otherwise
|
||||
* @throws SQLException if a problem occurs obtaining the transaction status
|
||||
*/
|
||||
public boolean isActive() throws SQLException {
|
||||
try {
|
||||
Transaction transaction = (Transaction) this.transactionRef.get();
|
||||
if (transaction == null) {
|
||||
return false;
|
||||
}
|
||||
int status = transaction.getStatus();
|
||||
return status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK;
|
||||
} catch (SystemException e) {
|
||||
throw (SQLException) new SQLException("Unable to get transaction status").initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Transaction getTransaction() throws SQLException {
|
||||
Transaction transaction = (Transaction) this.transactionRef.get();
|
||||
if (transaction == null) {
|
||||
throw new SQLException("Unable to enlist connection because the transaction has been garbage collected");
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
/**
|
||||
* A listener for transaction completion events.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface TransactionContextListener {
|
||||
|
||||
/**
|
||||
* Occurs after the transaction commits or rolls back.
|
||||
*
|
||||
* @param transactionContext the transaction context that completed
|
||||
* @param commited true if the transaction committed; false otherwise
|
||||
*/
|
||||
void afterCompletion(TransactionContext transactionContext, boolean commited);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAResource;
|
||||
|
||||
/**
|
||||
* TransactionRegistry tracks Connections and XAResources in a transacted environment for a single XAConnectionFactory.
|
||||
* </p> The TransactionRegistry hides the details of transaction processing from the existing DBCP pooling code, and
|
||||
* gives the ManagedConnection a way to enlist connections in a transaction, allowing for the maximal rescue of DBCP.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class TransactionRegistry {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
private final Map<Transaction, TransactionContext> caches = new WeakHashMap<Transaction, TransactionContext>();
|
||||
private final Map<Connection, XAResource> xaResources = new WeakHashMap<Connection, XAResource>();
|
||||
|
||||
/**
|
||||
* Creates a TransactionRegistry for the specified transaction manager.
|
||||
*
|
||||
* @param transactionManager the transaction manager used to enlist connections
|
||||
*/
|
||||
public TransactionRegistry(TransactionManager transactionManager){
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the association between a Connection and a XAResource. When a connection is enlisted in a transaction,
|
||||
* it is actually the XAResource that is given to the transaction manager.
|
||||
*
|
||||
* @param connection the JDBC connection
|
||||
* @param xaResource the XAResource which managed the connection within a transaction
|
||||
*/
|
||||
public synchronized void registerConnection(Connection connection, XAResource xaResource) {
|
||||
if (connection == null) throw new NullPointerException("connection is null");
|
||||
if (xaResource == null) throw new NullPointerException("xaResource is null");
|
||||
xaResources.put(connection, xaResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the XAResource registered for the connection.
|
||||
*
|
||||
* @param connection the connection
|
||||
* @return the XAResource registered for the connection; never null
|
||||
* @throws SQLException if the connection does not have a registered XAResource
|
||||
*/
|
||||
public synchronized XAResource getXAResource(Connection connection) throws SQLException {
|
||||
if (connection == null) throw new NullPointerException("connection is null");
|
||||
XAResource xaResource = (XAResource) xaResources.get(connection);
|
||||
if (xaResource == null) {
|
||||
throw new SQLException("Connection does not have a registered XAResource " + connection);
|
||||
}
|
||||
return xaResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active TransactionContext or null if not Transaction is active.
|
||||
*
|
||||
* @return the active TransactionContext or null if not Transaction is active
|
||||
* @throws SQLException if an error occurs while fetching the transaction
|
||||
*/
|
||||
public TransactionContext getActiveTransactionContext() throws SQLException {
|
||||
Transaction transaction = null;
|
||||
try {
|
||||
transaction = transactionManager.getTransaction();
|
||||
|
||||
// was there a transaction?
|
||||
if (transaction == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// is it active
|
||||
int status = transaction.getStatus();
|
||||
if (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK) {
|
||||
return null;
|
||||
}
|
||||
} catch (SystemException e) {
|
||||
throw (SQLException) new SQLException("Unable to determine current transaction ").initCause(e);
|
||||
}
|
||||
|
||||
// register the the context (or create a new one)
|
||||
synchronized (this) {
|
||||
TransactionContext cache = (TransactionContext) caches.get(transaction);
|
||||
if (cache == null) {
|
||||
cache = new TransactionContext(this, transaction);
|
||||
caches.put(transaction, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a destroyed connection from {@link TransactionRegistry}
|
||||
*
|
||||
* @param connection
|
||||
*/
|
||||
public synchronized void unregisterConnection(Connection connection) {
|
||||
xaResources.remove(connection);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.druid.pool.xa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* XAConnectionFactory is an extension of ConnectionFactory used to create connections in a transaction managed
|
||||
* environment. The XAConnectionFactory opperates like a normal ConnectionFactory except an TransactionRegistry is
|
||||
* provided from which the XAResource for a connection can be obtained. This allows the existing DBCP pool code to work
|
||||
* with XAConnections and gives a the ManagedConnection a way to enlist a connection in the the transaction.
|
||||
*
|
||||
* @author Dain Sundstrom
|
||||
* @author Rodney Waldhoff
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface XAConnectionFactory extends ConnectionFactory {
|
||||
|
||||
/**
|
||||
* Gets the TransactionRegistry for this connection factory which contains a the XAResource for every connection
|
||||
* created by this factory.
|
||||
*
|
||||
* @return the transaction registry for this connection factory
|
||||
*/
|
||||
TransactionRegistry getTransactionRegistry();
|
||||
|
||||
/**
|
||||
* Create a new {@link java.sql.Connection} in an implementation specific fashion. </p> An implementation can assume
|
||||
* that the caller of this will wrap the connection in a proxy that protects access to the setAutoCommit, commit and
|
||||
* rollback when enrolled in a XA transaction.
|
||||
*
|
||||
* @return a new {@link java.sql.Connection}
|
||||
* @throws java.sql.SQLException if a database error occurs creating the connection
|
||||
*/
|
||||
Connection createConnection() throws SQLException;
|
||||
}
|
||||
@@ -35,8 +35,8 @@ public class TestOracle_DruidDataSource extends TestCase {
|
||||
dataSource.setFilters("stat");
|
||||
dataSource.setExceptionSoter(OracleExceptionSorter.class.getName());
|
||||
|
||||
final int COUNT = 100;
|
||||
final int THREAD_COUNT = 1000;
|
||||
final int COUNT = 100 * 100;
|
||||
final int THREAD_COUNT = 10;
|
||||
final CountDownLatch startLatch = new CountDownLatch(1);
|
||||
final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user