提交 3697cea5 authored 作者: Thomas Mueller's avatar Thomas Mueller

When using the built-in connection pool, connections were not rolled back and…

When using the built-in connection pool, connections were not rolled back and autocommit was not enabled after closing.
上级 1f48b7b4
...@@ -35,7 +35,6 @@ import org.h2.message.Message; ...@@ -35,7 +35,6 @@ import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.util.JdbcConnectionListener;
import org.h2.util.ObjectUtils; import org.h2.util.ObjectUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
...@@ -80,7 +79,6 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -80,7 +79,6 @@ public class JdbcConnection extends TraceObject implements Connection {
private int savepointId; private int savepointId;
//## Java 1.4 end ## //## Java 1.4 end ##
private Trace trace; private Trace trace;
private JdbcConnectionListener listener;
private boolean isInternal; private boolean isInternal;
private String catalog; private String catalog;
private Statement executingStatement; private Statement executingStatement;
...@@ -122,6 +120,18 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -122,6 +120,18 @@ public class JdbcConnection extends TraceObject implements Connection {
} }
} }
/**
* INTERNAL
*/
public JdbcConnection(JdbcConnection clone) {
this.session = clone.session;
trace = session.getTrace();
int id = getNextId(TraceObject.CONNECTION);
setTrace(trace, TraceObject.CONNECTION, id);
this.user = clone.user;
this.url = clone.url;
}
/** /**
* INTERNAL * INTERNAL
*/ */
...@@ -261,13 +271,6 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -261,13 +271,6 @@ public class JdbcConnection extends TraceObject implements Connection {
} }
} }
/**
* INTERNAL
*/
public void setJdbcConnectionListener(JdbcConnectionListener listener) {
this.listener = listener;
}
/** /**
* INTERNAL * INTERNAL
*/ */
...@@ -281,14 +284,8 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -281,14 +284,8 @@ public class JdbcConnection extends TraceObject implements Connection {
* calling this method. If there is an uncommitted transaction, it will be * calling this method. If there is an uncommitted transaction, it will be
* rolled back. * rolled back.
*/ */
public void close() throws SQLException { public synchronized void close() throws SQLException {
synchronized (this) { closeConnection();
if (listener == null) {
closeConnection();
} else {
listener.closed(this);
}
}
} }
/** /**
...@@ -1252,12 +1249,13 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1252,12 +1249,13 @@ public class JdbcConnection extends TraceObject implements Connection {
} }
/** /**
* INTERNAL
* Check if this connection is closed. * Check if this connection is closed.
* *
* @return true if the session was re-connected * @return true if the session was re-connected
* @throws SQLException if the connection or session is closed * @throws SQLException if the connection or session is closed
*/ */
boolean checkClosed() throws SQLException { protected boolean checkClosed() throws SQLException {
if (session == null) { if (session == null) {
throw Message.getSQLException(ErrorCode.OBJECT_CLOSED); throw Message.getSQLException(ErrorCode.OBJECT_CLOSED);
} }
......
...@@ -23,7 +23,6 @@ package org.h2.jdbcx; ...@@ -23,7 +23,6 @@ package org.h2.jdbcx;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap;
import java.util.Stack; import java.util.Stack;
import javax.sql.ConnectionEvent; import javax.sql.ConnectionEvent;
...@@ -66,7 +65,6 @@ public class JdbcConnectionPool implements DataSource { ...@@ -66,7 +65,6 @@ public class JdbcConnectionPool implements DataSource {
private final ConnectionPoolDataSource dataSource; private final ConnectionPoolDataSource dataSource;
private final Stack recycledConnections = new Stack(); private final Stack recycledConnections = new Stack();
private final HashMap poolToConnMap = new HashMap();
private final PoolConnectionEventListener poolConnectionEventListener = new PoolConnectionEventListener(); private final PoolConnectionEventListener poolConnectionEventListener = new PoolConnectionEventListener();
private PrintWriter logWriter; private PrintWriter logWriter;
private int maxConnections = 10; private int maxConnections = 10;
...@@ -169,7 +167,6 @@ public class JdbcConnectionPool implements DataSource { ...@@ -169,7 +167,6 @@ public class JdbcConnectionPool implements DataSource {
PooledConnection pc = (PooledConnection) recycledConnections.pop(); PooledConnection pc = (PooledConnection) recycledConnections.pop();
try { try {
pc.close(); pc.close();
poolToConnMap.remove(pc);
} catch (SQLException e2) { } catch (SQLException e2) {
if (e == null) { if (e == null) {
e = e2; e = e2;
...@@ -222,12 +219,7 @@ public class JdbcConnectionPool implements DataSource { ...@@ -222,12 +219,7 @@ public class JdbcConnectionPool implements DataSource {
} else { } else {
pc = dataSource.getPooledConnection(); pc = dataSource.getPooledConnection();
} }
Connection conn; Connection conn = pc.getConnection();
conn = (Connection) poolToConnMap.get(pc);
if (conn == null) {
conn = pc.getConnection();
poolToConnMap.put(pc, conn);
}
activeConnections++; activeConnections++;
pc.addConnectionEventListener(poolConnectionEventListener); pc.addConnectionEventListener(poolConnectionEventListener);
return conn; return conn;
...@@ -260,7 +252,6 @@ public class JdbcConnectionPool implements DataSource { ...@@ -260,7 +252,6 @@ public class JdbcConnectionPool implements DataSource {
private void closeConnection(PooledConnection pc) { private void closeConnection(PooledConnection pc) {
try { try {
pc.close(); pc.close();
poolToConnMap.remove(pc);
} catch (SQLException e) { } catch (SQLException e) {
log("Error while closing database connection: " + e.toString()); log("Error while closing database connection: " + e.toString());
} }
......
...@@ -19,13 +19,14 @@ import javax.sql.XAConnection; ...@@ -19,13 +19,14 @@ import javax.sql.XAConnection;
import javax.transaction.xa.XAException; import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource; import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid; import javax.transaction.xa.Xid;
import org.h2.constant.ErrorCode;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.util.ByteUtils; import org.h2.util.ByteUtils;
import org.h2.util.JdbcConnectionListener;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
//## Java 1.4 end ## //## Java 1.4 end ##
import org.h2.message.Message;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
/*## Java 1.6 begin ## /*## Java 1.6 begin ##
...@@ -39,7 +40,7 @@ import javax.sql.StatementEventListener; ...@@ -39,7 +40,7 @@ import javax.sql.StatementEventListener;
*/ */
public class JdbcXAConnection extends TraceObject public class JdbcXAConnection extends TraceObject
//## Java 1.4 begin ## //## Java 1.4 begin ##
implements XAConnection, XAResource, JdbcConnectionListener implements XAConnection, XAResource
//## Java 1.4 end ## //## Java 1.4 end ##
{ {
...@@ -48,9 +49,8 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -48,9 +49,8 @@ implements XAConnection, XAResource, JdbcConnectionListener
private JdbcDataSourceFactory factory; private JdbcDataSourceFactory factory;
private String url, user; private String url, user;
private char[] password; private JdbcConnection physicalConn;
private JdbcConnection connSentinel; private PooledJdbcConnection handleConn;
private JdbcConnection conn;
private ArrayList listeners = new ArrayList(); private ArrayList listeners = new ArrayList();
private Xid currentTransaction; private Xid currentTransaction;
private int currentTransactionId; private int currentTransactionId;
...@@ -64,9 +64,10 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -64,9 +64,10 @@ implements XAConnection, XAResource, JdbcConnectionListener
setTrace(factory.getTrace(), TraceObject.XA_DATA_SOURCE, id); setTrace(factory.getTrace(), TraceObject.XA_DATA_SOURCE, id);
this.url = url; this.url = url;
this.user = user; this.user = user;
this.password = password; Properties info = new Properties();
connSentinel = openConnection(); info.setProperty("user", user);
getConnection(); info.put("password", StringUtils.cloneCharArray(password));
physicalConn = new JdbcConnection(url, info);
} }
//## Java 1.4 end ## //## Java 1.4 end ##
...@@ -91,33 +92,33 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -91,33 +92,33 @@ implements XAConnection, XAResource, JdbcConnectionListener
//## Java 1.4 begin ## //## Java 1.4 begin ##
public void close() throws SQLException { public void close() throws SQLException {
debugCodeCall("close"); debugCodeCall("close");
try { if (handleConn != null) {
closeConnection(conn); handleConn.close();
closeConnection(connSentinel); }
} finally { if (physicalConn != null) {
conn = null; try {
connSentinel = null; physicalConn.close();
} finally {
physicalConn = null;
}
} }
} }
//## Java 1.4 end ## //## Java 1.4 end ##
/** /**
* Get a new connection. This method is usually called by the connection * Get a connection that is a handle to the physical connection. This method is usually called by the connection
* pool when there are no more connections in the pool. * pool. This method closes the last connection handle if one exists.
* *
* @return the connection * @return the connection
* @throws SQLException
*/ */
//## Java 1.4 begin ## //## Java 1.4 begin ##
public Connection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
debugCodeCall("getConnection"); debugCodeCall("getConnection");
if (conn != null) { if (handleConn != null) {
closeConnection(conn); handleConn.close();
conn = null;
} }
conn = openConnection(); handleConn = new PooledJdbcConnection(physicalConn);
conn.setJdbcConnectionListener(this); return handleConn;
return conn;
} }
//## Java 1.4 end ## //## Java 1.4 end ##
...@@ -130,9 +131,6 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -130,9 +131,6 @@ implements XAConnection, XAResource, JdbcConnectionListener
public void addConnectionEventListener(ConnectionEventListener listener) { public void addConnectionEventListener(ConnectionEventListener listener) {
debugCode("addConnectionEventListener(listener);"); debugCode("addConnectionEventListener(listener);");
listeners.add(listener); listeners.add(listener);
if (conn != null) {
conn.setJdbcConnectionListener(this);
}
} }
//## Java 1.4 end ## //## Java 1.4 end ##
...@@ -152,7 +150,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -152,7 +150,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
* INTERNAL * INTERNAL
*/ */
//## Java 1.4 begin ## //## Java 1.4 begin ##
public void fatalErrorOccurred(JdbcConnection conn, SQLException e) throws SQLException { public void fatalErrorOccurred(PooledJdbcConnection conn, SQLException e) throws SQLException {
debugCode("fatalErrorOccurred(conn, e);"); debugCode("fatalErrorOccurred(conn, e);");
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i); ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i);
...@@ -167,13 +165,14 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -167,13 +165,14 @@ implements XAConnection, XAResource, JdbcConnectionListener
* INTERNAL * INTERNAL
*/ */
//## Java 1.4 begin ## //## Java 1.4 begin ##
public void closed(JdbcConnection conn) { void closedHandle() {
debugCode("closed(conn);"); debugCode("closedHandle();");
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i); ConnectionEventListener listener = (ConnectionEventListener) listeners.get(i);
ConnectionEvent event = new ConnectionEvent(this); ConnectionEvent event = new ConnectionEvent(this);
listener.connectionClosed(event); listener.connectionClosed(event);
} }
handleConn = null;
} }
//## Java 1.4 end ## //## Java 1.4 end ##
...@@ -230,7 +229,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -230,7 +229,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
checkOpen(); checkOpen();
Statement stat = null; Statement stat = null;
try { try {
stat = conn.createStatement(); stat = physicalConn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY TRANSACTION"); ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY TRANSACTION");
ArrayList list = new ArrayList(); ArrayList list = new ArrayList();
while (rs.next()) { while (rs.next()) {
...@@ -269,7 +268,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -269,7 +268,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
} }
Statement stat = null; Statement stat = null;
try { try {
stat = conn.createStatement(); stat = physicalConn.createStatement();
currentTransactionId = nextTransactionId++; currentTransactionId = nextTransactionId++;
stat.execute("PREPARE COMMIT TX_" + currentTransactionId); stat.execute("PREPARE COMMIT TX_" + currentTransactionId);
} catch (SQLException e) { } catch (SQLException e) {
...@@ -307,7 +306,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -307,7 +306,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
debugCode("rollback("+quoteXid(xid)+");"); debugCode("rollback("+quoteXid(xid)+");");
} }
try { try {
conn.rollback(); physicalConn.rollback();
} catch (SQLException e) { } catch (SQLException e) {
throw convertException(e); throw convertException(e);
} }
...@@ -356,7 +355,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -356,7 +355,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
throw new XAException(XAException.XAER_NOTA); throw new XAException(XAException.XAER_NOTA);
} }
try { try {
conn.setAutoCommit(false); physicalConn.setAutoCommit(false);
} catch (SQLException e) { } catch (SQLException e) {
throw convertException(e); throw convertException(e);
} }
...@@ -379,9 +378,9 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -379,9 +378,9 @@ implements XAConnection, XAResource, JdbcConnectionListener
Statement stat = null; Statement stat = null;
try { try {
if (onePhase) { if (onePhase) {
conn.commit(); physicalConn.commit();
} else { } else {
stat = conn.createStatement(); stat = physicalConn.createStatement();
stat.execute("COMMIT TRANSACTION TX_" + currentTransactionId); stat.execute("COMMIT TRANSACTION TX_" + currentTransactionId);
} }
} catch (SQLException e) { } catch (SQLException e) {
...@@ -423,24 +422,6 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -423,24 +422,6 @@ implements XAConnection, XAResource, JdbcConnectionListener
return getTraceObjectName() + ": url=" + url + " user=" + user; 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.put("password", StringUtils.cloneCharArray(password));
JdbcConnection conn = new JdbcConnection(url, info);
conn.setJdbcConnectionListener(this);
if (currentTransaction != null) {
conn.setAutoCommit(false);
}
return conn;
}
private XAException convertException(SQLException e) { private XAException convertException(SQLException e) {
XAException xa = new XAException(e.getMessage()); XAException xa = new XAException(e.getMessage());
xa.initCause(e); xa.initCause(e);
...@@ -497,10 +478,43 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -497,10 +478,43 @@ implements XAConnection, XAResource, JdbcConnectionListener
} }
private void checkOpen() throws XAException { private void checkOpen() throws XAException {
if (conn == null) { if (physicalConn == null) {
throw new XAException(XAException.XAER_RMERR); throw new XAException(XAException.XAER_RMERR);
} }
} }
//## Java 1.4 end ## //## Java 1.4 end ##
/**
* A pooled connection.
*/
class PooledJdbcConnection extends JdbcConnection {
private boolean isClosed;
public PooledJdbcConnection(JdbcConnection conn) throws SQLException {
super(conn);
}
public synchronized void close() throws SQLException {
if (!isClosed) {
rollback();
setAutoCommit(true);
closedHandle();
isClosed = true;
}
}
public synchronized boolean isClosed() throws SQLException {
return isClosed || super.isClosed();
}
protected synchronized boolean checkClosed() throws SQLException {
if (isClosed) {
throw Message.getSQLException(ErrorCode.OBJECT_CLOSED);
}
return super.checkClosed();
}
}
} }
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.sql.SQLException;
import org.h2.jdbc.JdbcConnection;
/**
* The JDBC connection listener is used internally by the H2 XA connection.
*/
public interface JdbcConnectionListener {
// TODO pooled connection: make sure
// fatalErrorOccurred is called in the right situations
/**
* A fatal error occurred.
*
* @param conn the connection
* @param e the exception
*/
void fatalErrorOccurred(JdbcConnection conn, SQLException e) throws SQLException;
/**
* A connection was closed
*
* @param conn the connection
*/
void closed(JdbcConnection conn);
}
...@@ -31,6 +31,7 @@ public class TestConnectionPool extends TestBase { ...@@ -31,6 +31,7 @@ public class TestConnectionPool extends TestBase {
public void test() throws Exception { public void test() throws Exception {
deleteDb("connectionPool"); deleteDb("connectionPool");
testUncommittedTransaction();
testPerformance(); testPerformance();
testKeepOpen(); testKeepOpen();
testConnect(); testConnect();
...@@ -38,6 +39,21 @@ public class TestConnectionPool extends TestBase { ...@@ -38,6 +39,21 @@ public class TestConnectionPool extends TestBase {
deleteDb("connectionPool"); deleteDb("connectionPool");
} }
private void testUncommittedTransaction() throws SQLException {
String url = getURL("connectionPool", true), user = getUser(), password = getPassword();
JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password);
Connection conn1 = man.getConnection();
assertTrue(conn1.getAutoCommit());
conn1.setAutoCommit(false);
conn1.close();
assertTrue(conn1.isClosed());
Connection conn2 = man.getConnection();
assertTrue(conn2.getAutoCommit());
man.dispose();
}
private void testPerformance() throws SQLException { private void testPerformance() throws SQLException {
String url = getURL("connectionPool", true), user = getUser(), password = getPassword(); String url = getURL("connectionPool", true), user = getUser(), password = getPassword();
JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password); JdbcConnectionPool man = JdbcConnectionPool.create(url, user, password);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论