From 6cceb116282ae7a31a61db5fc45fa45b6b479508 Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Fri, 2 Aug 2013 16:09:45 +0800 Subject: [PATCH] IDEMPIERE-1235 Add API to support the sharing of non-transactional connection within a single execution thread. --- .../compiere/db/CallableStatementProxy.java | 8 +- .../compiere/db/PreparedStatementProxy.java | 6 +- .../src/org/compiere/db/StatementProxy.java | 13 +-- .../db/util/AutoCommitConnectionBroker.java | 81 +++++++++++++++++++ 4 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 org.adempiere.base/src/org/idempiere/db/util/AutoCommitConnectionBroker.java diff --git a/org.adempiere.base/src/org/compiere/db/CallableStatementProxy.java b/org.adempiere.base/src/org/compiere/db/CallableStatementProxy.java index 4ed3b4ff43..91e8e21bad 100644 --- a/org.adempiere.base/src/org/compiere/db/CallableStatementProxy.java +++ b/org.adempiere.base/src/org/compiere/db/CallableStatementProxy.java @@ -13,13 +13,12 @@ package org.compiere.db; import java.sql.Connection; -import java.sql.ResultSet; import java.util.logging.Level; import org.adempiere.exceptions.DBException; import org.compiere.util.CStatementVO; -import org.compiere.util.DB; import org.compiere.util.Trx; +import org.idempiere.db.util.AutoCommitConnectionBroker; /** * Dynamic proxy for the CCallableStatement @@ -51,10 +50,7 @@ public class CallableStatementProxy extends PreparedStatementProxy { } else { - if (p_vo.getResultSetConcurrency() == ResultSet.CONCUR_UPDATABLE) - m_conn = DB.getConnectionRW (); - else - m_conn = DB.getConnectionRO(); + m_conn = AutoCommitConnectionBroker.getConnection(); conn = m_conn; } if (conn == null) diff --git a/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java b/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java index b744aa912c..457305122e 100644 --- a/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java +++ b/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java @@ -24,6 +24,7 @@ import org.compiere.util.CCachedRowSet; import org.compiere.util.CStatementVO; import org.compiere.util.DB; import org.compiere.util.Trx; +import org.idempiere.db.util.AutoCommitConnectionBroker; /** * Dynamic proxy for the CPreparedStatement interface @@ -60,10 +61,7 @@ public class PreparedStatementProxy extends StatementProxy { if (trx != null) { conn = trx.getConnection(); } else { - if (p_vo.getResultSetConcurrency() == ResultSet.CONCUR_UPDATABLE) - m_conn = DB.getConnectionRW(); - else - m_conn = DB.getConnectionRO(); + m_conn = AutoCommitConnectionBroker.getConnection(); conn = m_conn; } if (conn == null) diff --git a/org.adempiere.base/src/org/compiere/db/StatementProxy.java b/org.adempiere.base/src/org/compiere/db/StatementProxy.java index f3cc7af0e9..13cb249deb 100644 --- a/org.adempiere.base/src/org/compiere/db/StatementProxy.java +++ b/org.adempiere.base/src/org/compiere/db/StatementProxy.java @@ -31,6 +31,7 @@ import org.compiere.util.CStatementVO; import org.compiere.util.DB; import org.compiere.util.DisplayType; import org.compiere.util.Trx; +import org.idempiere.db.util.AutoCommitConnectionBroker; /** * @@ -152,10 +153,7 @@ public class StatementProxy implements InvocationHandler { } else { - if (p_vo.getResultSetConcurrency() == ResultSet.CONCUR_UPDATABLE) - m_conn = DB.getConnectionRW (); - else - m_conn = DB.getConnectionRO(); + m_conn = AutoCommitConnectionBroker.getConnection(); conn = m_conn; } if (conn == null) @@ -183,12 +181,7 @@ public class StatementProxy implements InvocationHandler { } finally { if (m_conn != null) { - try - { - m_conn.close(); - } - catch (Exception e) - {} + AutoCommitConnectionBroker.releaseConnection(m_conn); } m_conn = null; p_stmt = null; diff --git a/org.adempiere.base/src/org/idempiere/db/util/AutoCommitConnectionBroker.java b/org.adempiere.base/src/org/idempiere/db/util/AutoCommitConnectionBroker.java new file mode 100644 index 0000000000..a8243e9471 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/db/util/AutoCommitConnectionBroker.java @@ -0,0 +1,81 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.idempiere.db.util; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.compiere.util.DB; + +/** + * This class managed the sharing of non-transactional connection per thread. + * @author hengsin + * + */ +public class AutoCommitConnectionBroker { + private static ThreadLocal threadLocalConnection = new ThreadLocal() { + protected ConnectionReference initialValue() + { + return null; + } + }; + + /** + * Retrieve non-transactional connection for current thread. + * If none have been allocated yet, a new one will be created from the connection pool. + * @return Connection + */ + public static Connection getConnection() { + ConnectionReference connReference = threadLocalConnection.get(); + if (connReference != null) { + connReference.referenceCount++; + return connReference.connection; + } else { + Connection connection = DB.createConnection(true, false, Connection.TRANSACTION_READ_COMMITTED); + connReference = new ConnectionReference(connection); + threadLocalConnection.set(connReference); + return connection; + } + } + + /** + * Release connection. The connection goes back to pool if reference count is zero. + * @param conn + */ + public static void releaseConnection(Connection conn) { + ConnectionReference connReference = threadLocalConnection.get(); + if (connReference != null && connReference.connection == conn) { + connReference.referenceCount--; + if (connReference.referenceCount <= 0) { + threadLocalConnection.set(null); + try { + connReference.connection.close(); + } catch (SQLException e) {} + } + } else { + try { + conn.close(); + } catch (SQLException e) {} + } + } + + private static class ConnectionReference { + protected Connection connection; + protected int referenceCount; + protected ConnectionReference(Connection conn) { + connection = conn; + referenceCount = 1; + } + } +}