IDEMPIERE-120 Refactor Query timeout Implementation - move most postgresql specific code to DB_PostgreSQL
IDEMPIERE-121 Add API to support the locking of PO for update (transplanted from e99036fafdbdc294ebb0b847d675e0aac42c1843)
This commit is contained in:
parent
430f7e8e72
commit
0c15934a46
|
@ -25,6 +25,7 @@ import java.sql.Timestamp;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.compiere.dbPort.Convert;
|
import org.compiere.dbPort.Convert;
|
||||||
|
import org.compiere.model.PO;
|
||||||
|
|
||||||
//import org.compiere.util.CPreparedStatement;
|
//import org.compiere.util.CPreparedStatement;
|
||||||
|
|
||||||
|
@ -36,6 +37,10 @@ import org.compiere.dbPort.Convert;
|
||||||
*/
|
*/
|
||||||
public interface AdempiereDatabase
|
public interface AdempiereDatabase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** default lock timeout, 60 seconds **/
|
||||||
|
static final int LOCK_TIME_OUT = 60;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Database Name
|
* Get Database Name
|
||||||
* @return database short name
|
* @return database short name
|
||||||
|
@ -317,5 +322,22 @@ public interface AdempiereDatabase
|
||||||
*/
|
*/
|
||||||
public String addPagingSQL(String sql, int start, int end);
|
public String addPagingSQL(String sql, int start, int end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set statement/query timeout for connection
|
||||||
|
* @param conn
|
||||||
|
* @param timeout
|
||||||
|
* @return original timeout setting
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public int setStatementTimeout(Connection conn, int timeout) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock PO for update
|
||||||
|
* @param po
|
||||||
|
* @param timeout
|
||||||
|
* @return true if lock is granted
|
||||||
|
*/
|
||||||
|
public boolean forUpdate(PO po, int timeout);
|
||||||
|
|
||||||
} // AdempiereDatabase
|
} // AdempiereDatabase
|
||||||
|
|
||||||
|
|
|
@ -1012,51 +1012,18 @@ public final class DB
|
||||||
CPreparedStatement cs = ProxyFactory.newCPreparedStatement(ResultSet.TYPE_FORWARD_ONLY,
|
CPreparedStatement cs = ProxyFactory.newCPreparedStatement(ResultSet.TYPE_FORWARD_ONLY,
|
||||||
ResultSet.CONCUR_UPDATABLE, sql, trxName); // converted in call
|
ResultSet.CONCUR_UPDATABLE, sql, trxName); // converted in call
|
||||||
|
|
||||||
boolean autoCommit = false;
|
int currentTimeout = -1;
|
||||||
int currentTimeout = 0;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setParameters(cs, params);
|
setParameters(cs, params);
|
||||||
autoCommit = cs.getConnection().getAutoCommit();
|
|
||||||
//set timeout
|
//set timeout
|
||||||
if (timeOut > 0)
|
if (timeOut > 0)
|
||||||
{
|
{
|
||||||
if (DB.isPostgreSQL())
|
if (DB.isPostgreSQL())
|
||||||
{
|
currentTimeout = DB.getDatabase().setStatementTimeout(cs.getConnection(), timeOut);
|
||||||
try
|
|
||||||
{
|
|
||||||
Connection conn = cs.getConnection();
|
|
||||||
if (autoCommit)
|
|
||||||
{
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
ResultSet rs = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
rs = conn.createStatement().executeQuery("select current_setting('statement_timeout')");
|
|
||||||
if (rs.next())
|
|
||||||
currentTimeout = rs.getInt(1);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
DB.close(rs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement timeoutStatement = conn.createStatement();
|
|
||||||
timeoutStatement.execute("SET LOCAL statement_timeout TO " + ( timeOut * 1000 ));
|
|
||||||
if (log.isLoggable(Level.FINEST))
|
|
||||||
{
|
|
||||||
log.finest("Set statement timeout to " + timeOut);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cs.setQueryTimeout(timeOut);
|
cs.setQueryTimeout(timeOut);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
no = cs.executeUpdate();
|
no = cs.executeUpdate();
|
||||||
// No Transaction - Commit
|
// No Transaction - Commit
|
||||||
if (trxName == null)
|
if (trxName == null)
|
||||||
|
@ -1082,31 +1049,7 @@ public final class DB
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (autoCommit)
|
DB.getDatabase().setStatementTimeout(cs.getConnection(), currentTimeout);
|
||||||
{
|
|
||||||
cs.getConnection().setAutoCommit(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (currentTimeout > 0)
|
|
||||||
{
|
|
||||||
Statement timeoutStatement = cs.getConnection().createStatement();
|
|
||||||
timeoutStatement.execute("SET LOCAL statement_timeout TO " + ( currentTimeout * 1000 ));
|
|
||||||
if (log.isLoggable(Level.FINEST))
|
|
||||||
{
|
|
||||||
log.finest("Reset statement timeout to " + currentTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Statement timeoutStatement = cs.getConnection().createStatement();
|
|
||||||
timeoutStatement.execute("SET LOCAL statement_timeout TO Default");
|
|
||||||
if (log.isLoggable(Level.FINEST))
|
|
||||||
{
|
|
||||||
log.finest("Reset statement timeout to default");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (SQLException e) {}
|
catch (SQLException e) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.sql.DatabaseMetaData;
|
||||||
import java.sql.Driver;
|
import java.sql.Driver;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
@ -40,6 +41,7 @@ import org.adempiere.exceptions.DBException;
|
||||||
import org.compiere.Adempiere;
|
import org.compiere.Adempiere;
|
||||||
import org.compiere.dbPort.Convert;
|
import org.compiere.dbPort.Convert;
|
||||||
import org.compiere.dbPort.Convert_Oracle;
|
import org.compiere.dbPort.Convert_Oracle;
|
||||||
|
import org.compiere.model.PO;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.DisplayType;
|
import org.compiere.util.DisplayType;
|
||||||
|
@ -1206,4 +1208,54 @@ public class DB_Oracle implements AdempiereDatabase
|
||||||
catch (Exception e) {}
|
catch (Exception e) {}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setStatementTimeout(Connection conn, int timeout) throws SQLException {
|
||||||
|
//not supported by oracle
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean forUpdate(PO po, int timeout) {
|
||||||
|
//only can lock for update if using trx
|
||||||
|
if (po.get_TrxName() == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String[] keyColumns = po.get_KeyColumns();
|
||||||
|
if (keyColumns != null && keyColumns.length > 0 && !po.is_new()) {
|
||||||
|
StringBuffer sqlBuffer = new StringBuffer(" SELECT ");
|
||||||
|
sqlBuffer.append(keyColumns[0])
|
||||||
|
.append(" FROM ")
|
||||||
|
.append(po.get_TableName())
|
||||||
|
.append(" WHERE ");
|
||||||
|
for(int i = 0; i < keyColumns.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sqlBuffer.append(" AND ");
|
||||||
|
sqlBuffer.append(keyColumns[i]).append(" = ? ");
|
||||||
|
}
|
||||||
|
sqlBuffer.append(" FOR UPDATE ");
|
||||||
|
sqlBuffer.append(" WAIT ").append((timeout > 0 ? timeout : LOCK_TIME_OUT));
|
||||||
|
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
stmt = DB.prepareStatement(sqlBuffer.toString(),
|
||||||
|
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE, po.get_TrxName());
|
||||||
|
for(int i = 0; i < keyColumns.length; i++) {
|
||||||
|
stmt.setObject(i+1, po.get_Value(keyColumns[i]));
|
||||||
|
}
|
||||||
|
rs = stmt.executeQuery();
|
||||||
|
if (rs.next()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.log(Level.INFO, e.getLocalizedMessage(), e);
|
||||||
|
} finally {
|
||||||
|
DB.close(rs, stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // DB_Oracle
|
} // DB_Oracle
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.math.BigDecimal;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
@ -39,6 +40,7 @@ import org.adempiere.db.postgresql.PostgreSQLBundleActivator;
|
||||||
import org.adempiere.exceptions.DBException;
|
import org.adempiere.exceptions.DBException;
|
||||||
import org.compiere.dbPort.Convert;
|
import org.compiere.dbPort.Convert;
|
||||||
import org.compiere.dbPort.Convert_PostgreSQL;
|
import org.compiere.dbPort.Convert_PostgreSQL;
|
||||||
|
import org.compiere.model.PO;
|
||||||
import org.compiere.util.CCache;
|
import org.compiere.util.CCache;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
|
@ -928,4 +930,78 @@ public class DB_PostgreSQL implements AdempiereDatabase
|
||||||
catch (Exception e) {}
|
catch (Exception e) {}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setStatementTimeout(Connection conn, int timeOut) throws SQLException {
|
||||||
|
int currentTimeout = 0;
|
||||||
|
boolean autoCommit = conn.getAutoCommit();
|
||||||
|
ResultSet rs = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rs = conn.createStatement().executeQuery("select current_setting('statement_timeout')");
|
||||||
|
if (rs.next())
|
||||||
|
currentTimeout = rs.getInt(1) / 1000;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DB.close(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement timeoutStatement = conn.createStatement();
|
||||||
|
String sql = "SET " + (autoCommit ? "SESSION" : "LOCAL") + " statement_timeout TO " + ( timeOut > 0 ? Integer.toString(timeOut * 1000) : " DEFAULT ");
|
||||||
|
timeoutStatement.execute(sql);
|
||||||
|
if (log.isLoggable(Level.FINEST))
|
||||||
|
{
|
||||||
|
log.finest("Set statement timeout to " + timeOut);
|
||||||
|
}
|
||||||
|
return currentTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean forUpdate(PO po, int timeout) {
|
||||||
|
//only can lock for update if using trx
|
||||||
|
if (po.get_TrxName() == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String[] keyColumns = po.get_KeyColumns();
|
||||||
|
if (keyColumns != null && keyColumns.length > 0 && !po.is_new()) {
|
||||||
|
StringBuffer sqlBuffer = new StringBuffer(" SELECT ");
|
||||||
|
sqlBuffer.append(keyColumns[0])
|
||||||
|
.append(" FROM ")
|
||||||
|
.append(po.get_TableName())
|
||||||
|
.append(" WHERE ");
|
||||||
|
for(int i = 0; i < keyColumns.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sqlBuffer.append(" AND ");
|
||||||
|
sqlBuffer.append(keyColumns[i]).append(" = ? ");
|
||||||
|
}
|
||||||
|
sqlBuffer.append(" FOR UPDATE ");
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
int currentTimeout = -1;
|
||||||
|
try {
|
||||||
|
stmt = DB.prepareStatement(sqlBuffer.toString(),
|
||||||
|
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE, po.get_TrxName());
|
||||||
|
for(int i = 0; i < keyColumns.length; i++) {
|
||||||
|
stmt.setObject(i+1, po.get_Value(keyColumns[i]));
|
||||||
|
}
|
||||||
|
currentTimeout = setStatementTimeout(stmt.getConnection(), (timeout > 0 ? timeout : LOCK_TIME_OUT));
|
||||||
|
|
||||||
|
rs = stmt.executeQuery();
|
||||||
|
if (rs.next()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.log(Level.INFO, e.getLocalizedMessage(), e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
setStatementTimeout(stmt.getConnection(), currentTimeout);
|
||||||
|
} catch (SQLException e) {}
|
||||||
|
DB.close(rs, stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // DB_PostgreSQL
|
} // DB_PostgreSQL
|
||||||
|
|
Loading…
Reference in New Issue