📄 jdbcxaconnection.java
字号:
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.jdbcx;
//#ifdef JDK14
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Properties;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.h2.util.ByteUtils;
import org.h2.util.JdbcConnectionListener;
import org.h2.util.JdbcUtils;
import org.h2.jdbc.JdbcConnection;
//#endif
import org.h2.message.TraceObject;
//#ifdef JDK16
/*
import javax.sql.StatementEventListener;
*/
//#endif
/**
* This class provides support for distributed transactions.
* An application developer usually does not use this interface.
* It is used by the transaction manager internally.
*/
public class JdbcXAConnection extends TraceObject
//#ifdef JDK14
implements XAConnection, XAResource, JdbcConnectionListener
//#endif
{
//#ifdef JDK14
private JdbcDataSourceFactory factory;
private String url, user, password;
private JdbcConnection connSentinel;
private JdbcConnection conn;
private ArrayList listeners = new ArrayList();
private Xid currentTransaction;
private int currentTransactionId;
private static int nextTransactionId;
static {
org.h2.Driver.load();
}
JdbcXAConnection(JdbcDataSourceFactory factory, int id, String url, String user, String password) throws SQLException {
this.factory = factory;
setTrace(factory.getTrace(), TraceObject.XA_DATA_SOURCE, id);
this.url = url;
this.user = user;
this.password = password;
connSentinel = openConnection();
getConnection();
}
//#endif
/**
* Get the XAResource object.
*
* @return itself
*/
//#ifdef JDK14
public XAResource getXAResource() throws SQLException {
debugCodeCall("getXAResource");
return this;
}
//#endif
/**
* Close the physical connection.
* This method is usually called by the connection pool.
*/
//#ifdef JDK14
public void close() throws SQLException {
debugCodeCall("close");
try {
closeConnection(conn);
closeConnection(connSentinel);
} finally {
conn = null;
connSentinel = null;
}
}
//#endif
/**
* Get a new connection. This method is usually called by the connection
* pool when there are no more connections in the pool.
*
* @return the connection
*/
//#ifdef JDK14
public Connection getConnection() throws SQLException {
debugCodeCall("getConnection");
if (conn != null) {
closeConnection(conn);
conn = null;
}
conn = openConnection();
conn.setJdbcConnectionListener(this);
return conn;
}
//#endif
/**
* Register a new listener for the connection.
*
* @param listener the event listener
*/
//#ifdef JDK14
public void addConnectionEventListener(ConnectionEventListener listener) {
debugCode("addConnectionEventListener(listener)");
listeners.add(listener);
if (conn != null) {
conn.setJdbcConnectionListener(this);
}
}
//#endif
/**
* Remove the event listener.
*
* @param listener the event listener
*/
//#ifdef JDK14
public void removeConnectionEventListener(ConnectionEventListener listener) {
debugCode("removeConnectionEventListener(listener)");
listeners.remove(listener);
}
//#endif
/**
* INTERNAL
*/
//#ifdef JDK14
public void fatalErrorOccurred(JdbcConnection conn, SQLException e) throws SQLException {
debugCode("fatalErrorOccurred(conn, e)");
for (int i = 0; i < listeners.size(); i++) {
ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i);
ConnectionEvent event = new ConnectionEvent(this, e);
listener.connectionErrorOccurred(event);
}
close();
}
//#endif
/**
* INTERNAL
*/
//#ifdef JDK14
public void closed(JdbcConnection conn) {
debugCode("closed(conn)");
for (int i = 0; i < listeners.size(); i++) {
ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i);
ConnectionEvent event = new ConnectionEvent(this);
listener.connectionClosed(event);
}
}
//#endif
/**
* Get the transaction timeout.
*
* @return 0
*/
//#ifdef JDK14
public int getTransactionTimeout() throws XAException {
debugCodeCall("getTransactionTimeout");
return 0;
}
//#endif
/**
* Set the transaction timeout.
*
* @param seconds ignored
* @return false
*/
//#ifdef JDK14
public boolean setTransactionTimeout(int seconds) throws XAException {
debugCodeCall("setTransactionTimeout", seconds);
return false;
}
//#endif
/**
* Checks if this is the same XAResource.
*
* @param xares the other object
* @return true if this is the same object
*/
//#ifdef JDK14
public boolean isSameRM(XAResource xares) throws XAException {
debugCode("isSameRM(xares)");
return xares == this;
}
//#endif
/**
* Get the list of prepared transaction branches.
* This method is called by the transaction manager during recovery.
*
* @param flag TMSTARTRSCAN, TMENDRSCAN, or TMNOFLAGS. If no other flags are set,
* TMNOFLAGS must be used.
* @return zero or more Xid objects
*/
//#ifdef JDK14
public Xid[] recover(int flag) throws XAException {
debugCodeCall("recover", quoteFlags(flag));
checkOpen();
Statement stat = null;
try {
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY TRANSACTION");
ArrayList list = new ArrayList();
while (rs.next()) {
String tid = rs.getString("TRANSACTION");
int id = getNextId(XID);
Xid xid = new JdbcXid(factory, id, tid);
list.add(xid);
}
rs.close();
Xid[] result = new Xid[list.size()];
list.toArray(result);
return result;
} catch (SQLException e) {
getTrace().debug("throw XAException.XAER_RMERR", e);
throw new XAException(XAException.XAER_RMERR);
} finally {
JdbcUtils.closeSilently(stat);
}
}
//#endif
/**
* Prepare a transaction.
*
* @param xid the transaction id
*/
//#ifdef JDK14
public int prepare(Xid xid) throws XAException {
debugCode("prepare("+quoteXid(xid)+")");
checkOpen();
if (!currentTransaction.equals(xid)) {
getTrace().debug("throw XAException.XAER_INVAL");
throw new XAException(XAException.XAER_INVAL);
}
Statement stat = null;
try {
stat = conn.createStatement();
currentTransactionId = nextTransactionId++;
stat.execute("PREPARE COMMIT TX_" + currentTransactionId);
} catch (SQLException e) {
throw convertException(e);
} finally {
JdbcUtils.closeSilently(stat);
}
getTrace().debug("return XA_OK");
return XA_OK;
}
//#endif
/**
* Forget a transaction.
* This method does not have an effect for this database.
*
* @param xid the transaction id
*/
//#ifdef JDK14
public void forget(Xid xid) throws XAException {
debugCode("forget("+quoteXid(xid)+")");
}
//#endif
/**
* Roll back a transaction.
*
* @param xid the transaction id
*/
//#ifdef JDK14
public void rollback(Xid xid) throws XAException {
debugCode("rollback("+quoteXid(xid)+")");
try {
conn.rollback();
} catch (SQLException e) {
throw convertException(e);
}
getTrace().debug("rolled back");
currentTransaction = null;
}
//#endif
/**
* End a transaction.
*
* @param xid the transaction id
* @param flags TMSUCCESS, TMFAIL, or TMSUSPEND
*/
//#ifdef JDK14
public void end(Xid xid, int flags) throws XAException {
debugCode("end("+quoteXid(xid)+", "+quoteFlags(flags)+")");
// TODO transaction end: implement this method
if (flags == TMSUSPEND) {
return;
}
if (!currentTransaction.equals(xid)) {
getTrace().debug("throw XAException.XAER_OUTSIDE");
throw new XAException(XAException.XAER_OUTSIDE);
}
}
//#endif
/**
* Start or continue to work on a transaction.
*
* @param xid the transaction id
* @param flags TMNOFLAGS, TMJOIN, or TMRESUME
*/
//#ifdef JDK14
public void start(Xid xid, int flags) throws XAException {
debugCode("start("+quoteXid(xid)+", "+quoteFlags(flags)+")");
if (flags == TMRESUME) {
return;
}
if (currentTransaction != null) {
getTrace().debug("throw XAException.XAER_NOTA");
throw new XAException(XAException.XAER_NOTA);
}
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
throw convertException(e);
}
getTrace().debug("currentTransaction=xid");
currentTransaction = xid;
}
//#endif
/**
* Commit a transaction.
*
* @param xid the transaction id
* @param onePhase use a one-phase protocol if true
*/
//#ifdef JDK14
public void commit(Xid xid, boolean onePhase) throws XAException {
debugCode("commit("+quoteXid(xid)+", "+onePhase+")");
Statement stat = null;
try {
if (onePhase) {
conn.commit();
} else {
stat = conn.createStatement();
stat.execute("COMMIT TRANSACTION TX_" + currentTransactionId);
}
} catch (SQLException e) {
throw convertException(e);
} finally {
JdbcUtils.closeSilently(stat);
}
getTrace().debug("committed");
currentTransaction = null;
}
//#endif
/**
* [Not supported] Add a statement event listener.
*
* @param listener the new statement event listener
*/
//#ifdef JDK16
/*
public void addStatementEventListener(StatementEventListener listener) {
throw new UnsupportedOperationException();
}
*/
//#endif
/**
* [Not supported] Remove a statement event listener.
*
* @param listener the statement event listener
*/
//#ifdef JDK16
/*
public void removeStatementEventListener(StatementEventListener listener) {
throw new UnsupportedOperationException();
}
*/
//#endif
/**
* INTERNAL
*/
//#ifdef JDK14
public String toString() {
return getTraceObjectName() + ": url=" + url + " user=" + user;
}
private void closeConnection(JdbcConnection conn) throws SQLException {
if (conn != null) {
conn.closeConnection();
}
}
private JdbcConnection openConnection() throws SQLException {
Properties info = new Properties();
info.setProperty("user", user);
info.setProperty("password", password);
JdbcConnection conn = new JdbcConnection(url, info);
conn.setJdbcConnectionListener(this);
if (currentTransaction != null) {
conn.setAutoCommit(false);
}
return conn;
}
private XAException convertException(SQLException e) {
getTrace().debug("throw XAException("+e.getMessage()+")");
return new XAException(e.getMessage());
}
private String quoteXid(Xid xid) {
StringBuffer buff = new StringBuffer();
buff.append("\"f:");
buff.append(xid.getFormatId());
buff.append(",bq:");
buff.append(ByteUtils.convertBytesToString(xid.getBranchQualifier()));
buff.append(",gx:");
buff.append(ByteUtils.convertBytesToString(xid.getGlobalTransactionId()));
buff.append(",c:");
buff.append(xid.getClass().getName());
buff.append("\"");
return buff.toString();
}
private String quoteFlags(int flags) {
StringBuffer buff = new StringBuffer();
if ((flags & XAResource.TMENDRSCAN) != 0) {
buff.append("|XAResource.TMENDRSCAN");
}
if ((flags & XAResource.TMFAIL) != 0) {
buff.append("|XAResource.TMFAIL");
}
if ((flags & XAResource.TMJOIN) != 0) {
buff.append("|XAResource.TMJOIN");
}
if ((flags & XAResource.TMONEPHASE) != 0) {
buff.append("|XAResource.TMONEPHASE");
}
if ((flags & XAResource.TMRESUME) != 0) {
buff.append("|XAResource.TMRESUME");
}
if ((flags & XAResource.TMSTARTRSCAN) != 0) {
buff.append("|XAResource.TMSTARTRSCAN");
}
if ((flags & XAResource.TMSUCCESS) != 0) {
buff.append("|XAResource.TMSUCCESS");
}
if ((flags & XAResource.TMSUSPEND) != 0) {
buff.append("|XAResource.TMSUSPEND");
}
if ((flags & XAResource.XA_RDONLY) != 0) {
buff.append("|XAResource.XA_RDONLY");
}
if (buff.length() == 0) {
buff.append("|XAResource.TMNOFLAGS");
}
return buff.toString().substring(1);
}
private void checkOpen() throws XAException {
if (conn == null) {
getTrace().debug("conn==null");
throw new XAException(XAException.XAER_RMERR);
}
}
//#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -