From 8ab72bcba27bf8017c9b47d78b7150ba40b26289 Mon Sep 17 00:00:00 2001 From: hengsin Date: Mon, 5 Dec 2022 23:48:23 +0800 Subject: [PATCH] IDEMPIERE-5509 Implement readonly query with using Trx (#1599) --- .../compiere/db/PreparedStatementProxy.java | 24 ++ .../src/org/compiere/db/ProxyFactory.java | 16 ++ .../src/org/compiere/util/DB.java | 226 ++++++++++++------ 3 files changed, 194 insertions(+), 72 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java b/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java index 457305122e..95b5a480f1 100644 --- a/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java +++ b/org.adempiere.base/src/org/compiere/db/PreparedStatementProxy.java @@ -45,6 +45,17 @@ public class PreparedStatementProxy extends StatementProxy { init(); } // PreparedStatementProxy + public PreparedStatementProxy(int resultSetType, int resultSetConcurrency, + String sql0, Connection connection) { + if (sql0 == null || sql0.length() == 0) + throw new IllegalArgumentException("sql required"); + + p_vo = new CStatementVO(resultSetType, resultSetConcurrency, DB + .getDatabase().convertStatement(sql0)); + + init(connection); + } // PreparedStatementProxy + public PreparedStatementProxy(CStatementVO vo) { super(vo); @@ -74,6 +85,19 @@ public class PreparedStatementProxy extends StatementProxy { } } + /** + * Initialise the prepared statement wrapper object + */ + protected void init(Connection connection) { + try { + p_stmt = connection.prepareStatement(p_vo.getSql(), p_vo + .getResultSetType(), p_vo.getResultSetConcurrency()); + } catch (Exception e) { + log.log(Level.SEVERE, p_vo.getSql(), e); + throw new DBException(e); + } + } + @Override protected RowSet getRowSet() { diff --git a/org.adempiere.base/src/org/compiere/db/ProxyFactory.java b/org.adempiere.base/src/org/compiere/db/ProxyFactory.java index 9e5edb4e46..8b2f8b3a2b 100644 --- a/org.adempiere.base/src/org/compiere/db/ProxyFactory.java +++ b/org.adempiere.base/src/org/compiere/db/ProxyFactory.java @@ -13,6 +13,7 @@ package org.compiere.db; import java.lang.reflect.Proxy; +import java.sql.Connection; import org.compiere.util.CCallableStatement; import org.compiere.util.CPreparedStatement; @@ -56,6 +57,21 @@ public class ProxyFactory { new PreparedStatementProxy(resultSetType, resultSetConcurrency, sql, trxName)); } + /** + * + * @param resultSetType + * @param resultSetConcurrency + * @param sql + * @param trxName + * @return CPreparedStatement proxy + */ + public static CPreparedStatement newCPreparedStatement(int resultSetType, + int resultSetConcurrency, String sql, Connection connection) { + return (CPreparedStatement)Proxy.newProxyInstance(CPreparedStatement.class.getClassLoader(), + new Class[]{CPreparedStatement.class}, + new PreparedStatementProxy(resultSetType, resultSetConcurrency, sql, connection)); + } + /** * * @param resultSetType diff --git a/org.adempiere.base/src/org/compiere/util/DB.java b/org.adempiere.base/src/org/compiere/util/DB.java index c78fec4ee7..25314975e0 100644 --- a/org.adempiere.base/src/org/compiere/util/DB.java +++ b/org.adempiere.base/src/org/compiere/util/DB.java @@ -711,6 +711,17 @@ public final class DB return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, trxName); } // prepareStatement + /** + * Prepare Statement + * @param sql + * @param trxName transaction + * @return Prepared Statement + */ + public static CPreparedStatement prepareStatement (Connection connection, String sql) + { + return prepareStatement(connection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } // prepareStatement + /** * Prepare Statement. * @param sql @@ -742,6 +753,23 @@ public final class DB return ProxyFactory.newCPreparedStatement(resultSetType, resultSetConcurrency, sql, trxName); } // prepareStatement + /** + * Prepare Statement. + * @param sql sql statement + * @param resultSetType - ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE + * @param resultSetConcurrency - ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE + * @param trxName transaction name + * @return Prepared Statement r/o or r/w depending on concur + */ + public static CPreparedStatement prepareStatement(Connection connection, String sql, + int resultSetType, int resultSetConcurrency) + { + if (sql == null || sql.length() == 0) + throw new IllegalArgumentException("No SQL"); + // + return ProxyFactory.newCPreparedStatement(resultSetType, resultSetConcurrency, sql, connection); + } // prepareStatement + /** * Create Read Only Statement * @return Statement @@ -1242,19 +1270,21 @@ public final class DB int retValue = -1; PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLValueEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); if (rs.next()) @@ -1264,9 +1294,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -1274,14 +1308,32 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } return retValue; } + private static void closeAndResetReadonlyConnection(Connection conn) { + try { + conn.setAutoCommit(true); + } catch (SQLException e) { + e.printStackTrace(); + } + try { + conn.setReadOnly(false); + } catch (SQLException e) { + e.printStackTrace(); + } + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + /** * Get String Value from sql * @param trxName optional transaction name @@ -1341,19 +1393,21 @@ public final class DB String retValue = null; PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLValueEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); if (rs.next()) @@ -1363,9 +1417,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -1373,9 +1431,9 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } return retValue; @@ -1440,19 +1498,21 @@ public final class DB BigDecimal retValue = null; PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLValueEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); if (rs.next()) @@ -1462,9 +1522,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -1472,9 +1536,9 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } return retValue; @@ -1540,19 +1604,21 @@ public final class DB Timestamp retValue = null; PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLValueEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); if (rs.next()) @@ -1562,9 +1628,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -1572,9 +1642,9 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } return retValue; @@ -2455,19 +2525,21 @@ public final class DB List retValue = new ArrayList(); PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLValueObjectsEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); @@ -2485,9 +2557,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -2495,9 +2571,9 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } return retValue; @@ -2516,19 +2592,21 @@ public final class DB List> rowsArray = new ArrayList>(); PreparedStatement pstmt = null; ResultSet rs = null; - Trx trx = null; + Connection conn = null; if (trxName == null) - { - trxName = Trx.createTrxName("getSQLArrayObjectsEx"); - trx = Trx.get(trxName, true); - } + conn = DB.createConnection(true, Connection.TRANSACTION_READ_COMMITTED); try { - if (trx != null) + if (conn != null) { - trx.getConnection().setReadOnly(true); + conn.setAutoCommit(false); + conn.setReadOnly(true); } - pstmt = prepareStatement(sql, trxName); + + if (conn != null) + pstmt = prepareStatement(conn, sql); + else + pstmt = prepareStatement(sql, trxName); setParameters(pstmt, params); rs = pstmt.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); @@ -2546,9 +2624,13 @@ public final class DB } catch (SQLException e) { - if (trx != null) + if (conn != null) { - trx.rollback(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } } throw new DBException(e, sql); } @@ -2556,9 +2638,9 @@ public final class DB { close(rs, pstmt); rs = null; pstmt = null; - if (trx != null) + if (conn != null) { - trx.close(); + closeAndResetReadonlyConnection(conn); } } if (rowsArray.size() == 0)