我正在研究遗留代码,因为我们遇到了主要的数据库连接问题(1000+ sleeping connections at all times
)以及如此缓慢的返回结果,所以我决定密切关注我们所谓的“Database Pooling
”架构。 / p>
显然我们有两个Database.java
和两个ConnectionPool.java
,一对在Web应用程序模块中,另一对在数据库模块中。
所以它看起来像这样:
package mil.dlas.database;
Database.java
ConnectionPool.java
package ti.dlas;
Database.java
ConnectionPool.java
package ti.dlas
public synchronized void getConn(ErrorBean myError)
{
try
{
try
{
if (this.webBasedConnection)
{
if(dataSource == null)
{
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/mydb");
}
if(dataSource == null)
{
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/mydb");
}
conn = dataSource.getConnection();
}
else
{
getConnInterfaceBased(myError);
}
}
catch (NamingException e)
{
e.printStackTrace();
getConnInterfaceBased(myError);
}
catch(SQLException e)
{
e.printStackTrace();
getConnInterfaceBased(myError);
}
}
catch(Exception ex)
{
ex.printStackTrace();
getConnInterfaceBased(myError);
}
}
public synchronized void insertOrUpdatePS(String query,Object[] param, ErrorBean eb)
{
java.sql.PreparedStatement pStat = null;
try
{
getConn(eb);
pStat = conn.prepareStatement(query);
for(int i=0; i<param.length;i++)
{
pStat.setObject(i+1,param[i]);
}
iRowsUpdated = pStat.executeUpdate();
}
catch(SQLException e)
{e.printStackTrace();}
catch(Exception e)
{e.printStackTrace();}
finally {
if(pStat!=null)
try {pStat.close();}
catch(SQLException e){}
returnConn();
}
}
/**ConnectionPool .java**/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;
public class ConnectionPool implements Runnable, java.io.Serializable{
private String driver, url, username, password;
private int maxConnections;
private boolean waitIfBusy;
private Vector availableConnections, busyConnections;
private boolean connectionPending = false;
public ConnectionPool(String driver, String url,
String username, String password,
int initialConnections,
int maxConnections,
boolean waitIfBusy)
throws SQLException {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
this.maxConnections = maxConnections;
this.waitIfBusy = waitIfBusy;
if (initialConnections > maxConnections) {
initialConnections = maxConnections;
}
availableConnections = new Vector(initialConnections);
busyConnections = new Vector();
for(int i=0; i<initialConnections; i++) {
availableConnections.addElement(makeNewConnection());
}
}
public synchronized Connection getConnection()
throws SQLException {
if (!availableConnections.isEmpty()) {
Connection existingConnection =
(Connection)availableConnections.lastElement();
int lastIndex = availableConnections.size() - 1;
availableConnections.removeElementAt(lastIndex);
if (existingConnection.isClosed()) {
notifyAll();
return(getConnection());
} else {
busyConnections.addElement(existingConnection);
return(existingConnection);
}
} else {
if ((totalConnections() < maxConnections) &&
!connectionPending) {
makeBackgroundConnection();
} else if (!waitIfBusy) {
throw new SQLException("Connection limit reached");
}
try {
wait();
} catch(InterruptedException ie) {}
return(getConnection());
}
}
private void makeBackgroundConnection() {
connectionPending = true;
try {
Thread connectThread = new Thread(this);
connectThread.start();
} catch(OutOfMemoryError oome) {}
}
public void run() {
try {
Connection connection = makeNewConnection();
synchronized(this) {
availableConnections.addElement(connection);
connectionPending = false;
notifyAll();
}
} catch(Exception e) { }
}
private Connection makeNewConnection()
throws SQLException {
try {
Class.forName(driver);
Connection connection =
DriverManager.getConnection(url, username, password);
return(connection);
} catch(ClassNotFoundException cnfe) {
throw new SQLException("Can't find class for driver: " +
driver);
}
}
public synchronized void free(Connection connection) {
busyConnections.removeElement(connection);
availableConnections.addElement(connection);
notifyAll();
}
public synchronized int totalConnections() {
return(availableConnections.size() +
busyConnections.size());
}
}
package mil.dlas.database;
public synchronized void getConn()
{
try
{
try
{
if(dataSource == null)
{
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/mydb");
}
conn = dataSource.getConnection();
webBasedConnection = true;
}
catch (NamingException e){getConnInterfaceBased}
catch(SQLException e){getConnInterfaceBased();}
}
catch(Exception ex){getConnInterfaceBased();}
}
public synchronized void insertOrUpdatePS(String query, Object[] param)
{
java.sql.PreparedStatement pStat = null;
String jobnumber = "";
try
{
getConn();
if(!webBasedConnection)
conn = checkOut();
pStat = conn.prepareStatement(query);
for(int i=0; i<param.length;i++)
{
if (i==0)
jobnumber = param[i].toString();
pStat.setObject(i+1,param[i]);
}
int insertUpdateReturnCode = pStat.executeUpdate();
ResultSet rs = pStat.getGeneratedKeys();
if (rs.next())
{
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
String columnOneName = rsmd.getColumnName(1);
for (int x = 1; x <= colCount; x++)
{
String key = rs.getString(x);
this.autoIncrementedID = key;
}
}
else
{
this.autoIncrementedID = "";
}
}
catch(SQLException e){e.printStackTrace();}
catch(Exception e){e.printStackTrace();}
finally
{
if(pStat!=null)
try {pStat.close();}
catch(SQLException e){}
if(this.webBasedConnection)
returnConn();
else
checkIn(conn);
}
}
package mil.dlas.database;
import java.util.*;
import java.sql.*;
public class ConnectionPool implements Runnable
{
private int m_InitialConnectionCount = 3;
private Vector m_AvailableConnections = new Vector();
private Vector m_UsedConnections = new Vector();
private String m_URLString = null;
private String m_UserName = null;
private String m_Password = null;
private Thread m_CleanupThread = null;
protected ConnectionPool(String urlString, String user, String passwd) throws SQLException
{
m_URLString = urlString;
m_UserName = user;
m_Password = passwd;
for(int cnt=0; cnt<m_InitialConnectionCount; cnt++)
{
m_AvailableConnections.addElement(getConnection());
}
m_CleanupThread = new Thread(this);
m_CleanupThread.start();
}
private Connection getConnection() throws SQLException
{
return DriverManager.getConnection(m_URLString, m_UserName, m_Password);
}
public synchronized Connection checkout() throws SQLException
{
Connection newConnxn = null;
if(m_AvailableConnections.size() == 0)
{
newConnxn = getConnection();
m_UsedConnections.addElement(newConnxn);
}
else
{
newConnxn = (Connection)m_AvailableConnections.lastElement();
m_AvailableConnections.removeElement(newConnxn);
m_UsedConnections.addElement(newConnxn);
}
return newConnxn;
}
public synchronized void checkin(Connection c)
{
if(c != null)
{
m_UsedConnections.removeElement(c);
m_AvailableConnections.addElement(c);
}
}
public int availableCount()
{
return m_AvailableConnections.size();
}
public void run()
{
Connection c = null;
try {
while(true)
{
synchronized(this)
{
while(m_AvailableConnections.size() > m_InitialConnectionCount)
{
c = (Connection)m_AvailableConnections.lastElement();
m_AvailableConnections.removeElement(c);
}
}
Thread.sleep(60000 * 1);
}
}
catch(Exception e) { e.printStackTrace(); }
finally {
try{if (c != null) c.close();}
catch(SQLException sqle) { sqle.printStackTrace(); }
}
}
public void closeConns() throws SQLException
{
try {
for(int cnt=0; cnt<=m_AvailableConnections.size(); cnt++)
{
Connection c = (Connection)m_AvailableConnections.lastElement();
c.close();
m_AvailableConnections.removeElement(c);
}
}
catch(Exception e) { e.printStackTrace(); }
}
}
在代码中,我看到对这两个类的调用:
Database db = new Database();
db.insertOrUpdatePS(qstring.toString(), param);
Database dbAddMember = (Database) ssb.getObject("db");
dbAddMember.insertOrUpdatePS(qstring, param, eb);
假设我们与我们使用的数据库不一致是否安全?
由于所有参与此工作的人已经离开了,我如何弄清楚为什么有人会使用其中一个而不是另一个?如果我应该考虑删除一个?
如何查找此处的某些内容是否导致泄漏?
有关如何处理此事的任何建议?
答案 0 :(得分:1)
老实说,代码绝对可怕。不是因为你有自定义数据库连接处理,而是因为遗留代码正在同步方法来获取数据库访问权限,这意味着一次只能执行一个SQL语句,这不好。
您不一定会将source activate
遗留代码归咎于连接池的解决方案,但在这个时代,您可以放心地假设有许多更好且经过验证的解决方案,这些解决方案可以在多年前编写。
许多用户对attempting
库有自己的意见,可以完成工作,但我会说我在几个项目中取得了很好的成功:
JTDS用于良好的数据库驱动程序(http://jtds.sourceforge.net/)
Atomikos for Transaction management(http://www.atomikos.com/Documentation/WebHome)
连接池的DBCP(https://commons.apache.org/proper/commons-dbcp/)
还有很多其他人。 无论如何,从我看到的情况来看,你肯定会看到改进决定用经过验证的真实库来替换自定义代码来完成工作。