|
这个主题共有 18 回复 / 2 页 [
1 2
下一页
]
|
|
|
|
|
|
[寻]连接池例子
|
发表: 2002年09月28日 11:16
|
回复
|
|
要求:
1.可以不依赖于任何特殊J2EE Server
2.代码越短越好
3.性能不要太差
4.有文档最好
哪位高手可以给个例子?
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月28日 14:06
|
回复
|
|
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月28日 14:30
|
回复
|
|
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月28日 15:27
|
回复
|
|
uitl.database.ConnectionManager 用队列保存min个连接,尾进头出。getConnection()检查队列中如有,从头弹出,如果这时候没有可用的,循环等待指定时间,如果还是没有(异常),返回null。后台的线程检查队列中的可用连接数目是否小于min,如果小于,生成并在队列尾部插入min-size个连接。用户freeConnection,如果size<max,插入尾部,否则释放。
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月28日 15:30
|
回复
|
|
|
用户freeConnection(conn),如果size 不小于max,插入队列尾部,否则释放这个conn
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月29日 13:34
|
回复
|
|
uitl.database.ConnectionManager 没有设置size的方法? 这是很奇怪的
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月29日 15:21
|
回复
|
|
|
uitl.database.ConnectionManager.getInstance()要求提供min和max,如果需要在运行中改变,可以自己加入setMin()之类的方法。
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月30日 10:24
|
回复
|
|
|
我想把你的例子改成就一个类ConnectionPool,没有内部类,你说可能吗?
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月30日 11:07
|
回复
|
|
还有,请教一下你在getConnection中的
//等待半个周期 wait(PERIOD / 2);
,但是整个程序中,并没有notify或者notifyAll语句啊
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月30日 14:05
|
回复
|
|
public static Connection getConnection() throws Exception { Connection connection = null; if (connectionPool.size() < NUM_OF_CONNECTION) { connection = Class.forName("my.sql.Driver"). getConnection("dbc:oracle:thin:@192.168.0.164:1521:ora9i"); connectionPool.add(connection); } else { if(conuter < NUM_OF_CONNECTION) counter++; else counter = 0; connection = (Connection)connectionPool.elementAT(counter% NUM_OF_CONNECTION ); } return connection; }
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年09月30日 14:36
|
回复
|
|
Re;"但是整个程序中,并没有notify或者notifyAll语句啊 " 哈哈,说句老实话,我对Thread这个东西真的不熟悉,到底有没有正确使用我不敢保证。是不是应该在run()里面增加可用连接后,notify()一下?我不知道这个, 请你指教。
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年10月02日 15:48
|
回复
|
|
import java.io.*; import java.sql.*; import java.text.*; import java.util.Date;
/** * DbConnectionBroker * A servlet-based broker for database connections. * Creates and manages a pool of database connections. * @version 1.0.13 3/12/02 * @author Marc A. Mnich */ public class DbConnectionBroker implements Runnable { private Thread runner; private Connection[] connPool; private int[] connStatus;
private long[] connLockTime, connCreateDate; private String[] connID; private String dbDriver, dbServer, dbLogin, dbPassword, logFileString; private int currConnections, connLast, minConns, maxConns, maxConnMSec, maxCheckoutSeconds, debugLevel;
//available: set to false on destroy, checked by getConnection() private boolean available=true;
private PrintWriter log; private SQLWarning currSQLWarning; private String pid;
private final int DEFAULTMAXCHECKOUTSECONDS=60; private final int DEFAULTDEBUGLEVEL=2; /** * Creates a new Connection Broker<br> * dbDriver: JDBC driver. e.g. 'oracle.jdbc.driver.OracleDriver'<br> * dbServer: JDBC connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'<br> * dbLogin: Database login name. e.g. 'Scott'<br> * dbPassword: Database password. e.g. 'Tiger'<br> * minConns: Minimum number of connections to start with.<br> * maxConns: Maximum number of connections in dynamic pool.<br> * logFileString: Absolute path name for log file. e.g. 'c:/temp/mylog.log' <br> * maxConnTime: Time in days between connection resets. (Reset does a basic cleanup)<br> * logAppend: Append to logfile (optional)<br> * maxCheckoutSeconds: Max time a connection can be checked out before being recycled. Zero value turns option off, default is 60 seconds. * debugLevel: Level of debug messages output to the log file. 0 -> no messages, 1 -> Errors, 2 -> Warnings, 3 -> Information */ public DbConnectionBroker(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, false, DEFAULTMAXCHECKOUTSECONDS, DEFAULTDEBUGLEVEL); }
/* * Special constructor to handle logfile append */ public DbConnectionBroker(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, logAppend, DEFAULTMAXCHECKOUTSECONDS, DEFAULTDEBUGLEVEL); }
/* * Special constructor to handle connection checkout expiration */ public DbConnectionBroker(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend, int maxCheckoutSeconds, int debugLevel) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, logAppend, maxCheckoutSeconds, debugLevel); }
private void setupBroker(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend, int maxCheckoutSeconds, int debugLevel) throws IOException { connPool = new Connection[maxConns]; connStatus = new int[maxConns]; connLockTime = new long[maxConns]; connCreateDate = new long[maxConns]; connID = new String[maxConns]; currConnections = minConns; this.maxConns = maxConns; this.dbDriver = dbDriver; this.dbServer = dbServer; this.dbLogin = dbLogin; this.dbPassword = dbPassword; this.logFileString = logFileString; this.maxCheckoutSeconds = maxCheckoutSeconds; this.debugLevel = debugLevel; maxConnMSec = (int)(maxConnTime * 86400000.0); //86400 sec/day if(maxConnMSec < 30000) { // Recycle no less than 30 seconds. maxConnMSec = 30000; }
try { log = new PrintWriter(new FileOutputStream(logFileString, logAppend),true); // Can't open the requested file. Open the default file. } catch (IOException e1) { try { log = new PrintWriter(new FileOutputStream("DCB_" + System.currentTimeMillis() + ".log", logAppend),true); } catch (IOException e2) { throw new IOException("Can't open any log file"); } }
// Write the pid file (used to clean up dead/broken connection) SimpleDateFormat formatter = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz"); Date nowc = new Date(); pid = formatter.format(nowc); BufferedWriter pidout = new BufferedWriter(new FileWriter(logFileString + "pid")); pidout.write(pid); pidout.close(); log.println("-----------------------------------------"); log.println("-----------------------------------------"); log.println("Starting DbConnectionBroker Version 1.0.13:"); log.println("dbDriver = " + dbDriver); log.println("dbServer = " + dbServer); log.println("dbLogin = " + dbLogin); log.println("log file = " + logFileString); log.println("minconnections = " + minConns); log.println("maxconnections = " + maxConns); log.println("Total refresh interval = " + maxConnTime + " days"); log.println("logAppend = " + logAppend); log.println("maxCheckoutSeconds = " + maxCheckoutSeconds); log.println("debugLevel = " + debugLevel); log.println("-----------------------------------------"); // Initialize the pool of connections with the mininum connections: // Problems creating connections may be caused during reboot when the // servlet is started before the database is ready. Handle this // by waiting and trying again. The loop allows 5 minutes for // db reboot. boolean connectionsSucceeded=false; int dbLoop=20; try { for(int i=1; i < dbLoop; i++) { try { for(int j=0; j < currConnections; j++) { createConn(j); } connectionsSucceeded=true; break; } catch (SQLException e){ if(debugLevel > 0) { log.println("--->Attempt (" + String.valueOf(i) + " of " + String.valueOf(dbLoop) + ") failed to create new connections set at startup: "); log.println(" " + e); log.println(" Will try again in 15 seconds..."); } try { Thread.sleep(15000); } catch(InterruptedException e1) {} } } if(!connectionsSucceeded) { // All attempts at connecting to db exhausted if(debugLevel > 0) { log.println("\r\nAll attempts at connecting to Database exhausted"); } throw new IOException(); } } catch (Exception e) { throw new IOException(); } // Fire up the background housekeeping thread
runner = new Thread(this); runner.start();
}//End DbConnectionBroker()
/** * Housekeeping thread. Runs in the background with low CPU overhead. * Connections are checked for warnings and closure and are periodically * restarted. * This thread is a catchall for corrupted * connections and prevents the buildup of open cursors. (Open cursors * result when the application fails to close a Statement). * This method acts as fault tolerance for bad connection/statement programming. */ public void run() { boolean forever = true; Statement stmt=null; String currCatalog=null; long maxCheckoutMillis = maxCheckoutSeconds * 1000;
while(forever) { // Make sure the log file is the one this instance opened // If not, clean it up! try { BufferedReader in = new BufferedReader(new FileReader(logFileString + "pid")); String curr_pid = in.readLine(); if(curr_pid.equals(pid)) { //log.println("They match = " + curr_pid); } else { //log.println("No match = " + curr_pid); log.close(); // Close all connections silently - they are definitely dead. for(int i=0; i < currConnections; i++) { try { connPool.close(); } catch (SQLException e1) {} // ignore } // Returning from the run() method kills the thread return; } in.close(); } catch (IOException e1) { log.println("Can't read the file for pid info: " + logFileString + "pid"); } // Get any Warnings on connections and print to event file for(int i=0; i < currConnections; i++) { try { currSQLWarning = connPool.getWarnings(); if(currSQLWarning != null) { if(debugLevel > 1) { log.println("Warnings on connection " + String.valueOf(i) + " " + currSQLWarning); } connPool.clearWarnings(); } } catch(SQLException e) { if(debugLevel > 1) { log.println("Cannot access Warnings: " + e); } } } for(int i=0; i < currConnections; i++) { // Do for each connection long age = System.currentTimeMillis() - connCreateDate;
try { // Test the connection with createStatement call synchronized(connStatus) { if(connStatus > 0) { // In use, catch it next time! // Check the time it's been checked out and recycle long timeInUse = System.currentTimeMillis() - connLockTime; if(debugLevel > 2) { log.println("Warning. Connection " + i + " in use for " + timeInUse + " ms"); } if(maxCheckoutMillis != 0) { if(timeInUse > maxCheckoutMillis) { if(debugLevel > 1) { log.println("Warning. Connection " + i + " failed to be returned in time. Recycling..."); } throw new SQLException(); } } continue; } connStatus = 2; // Take offline (2 indicates housekeeping lock) } if(age > maxConnMSec) { // Force a reset at the max conn time throw new SQLException(); } stmt = connPool.createStatement(); connStatus = 0; // Connection is O.K. //log.println("Connection confirmed for conn = " + // String.valueOf(i)); // Some DBs return an object even if DB is shut down if(connPool.isClosed()) { throw new SQLException(); }
// Connection has a problem, restart it } catch(SQLException e) {
if(debugLevel > 1) { log.println(new Date().toString() + " ***** Recycling connection " + String.valueOf(i) + ":"); } try { connPool.close(); } catch(SQLException e0) { if(debugLevel > 0) { log.println("Error! Can't close connection! Might have been closed already. Trying to recycle anyway... (" + e0 + ")"); } }
try { createConn(i); } catch(SQLException e1) { if(debugLevel > 0) { log.println("Failed to create connection: " + e1); } connStatus = 0; // Can't open, try again next time } } finally { try{if(stmt != null) {stmt.close();}} catch(SQLException e1){}; } } try { Thread.sleep(20000); } // Wait 20 seconds for next cycle catch(InterruptedException e) { // Returning from the run method sets the internal // flag referenced by Thread.isAlive() to false. // This is required because we don't use stop() to // shutdown this thread. return; } } } // End run /** * This method hands out the connections in round-robin order. * This prevents a faulty connection from locking * up an application entirely. A browser 'refresh' will * get the next connection while the faulty * connection is cleaned up by the housekeeping thread. * * If the min number of threads are ever exhausted, new * threads are added up the the max thread count. * Finally, if all threads are in use, this method waits * 2 seconds and tries again, up to ten times. After that, it * returns a null. */ public Connection getConnection() { Connection conn=null;
if(available){ boolean gotOne = false; for(int outerloop=1; outerloop<=10; outerloop++) { try { int loop=0; int roundRobin = connLast + 1; if(roundRobin >= currConnections) roundRobin=0; do { synchronized(connStatus) { if((connStatus[roundRobin] < 1) && (! connPool[roundRobin].isClosed())) { conn = connPool[roundRobin]; connStatus[roundRobin]=1; connLockTime[roundRobin] = System.currentTimeMillis(); connLast = roundRobin; gotOne = true; break; } else { loop++; roundRobin++; if(roundRobin >= currConnections) roundRobin=0; } } } while((gotOne==false)&&(loop < currConnections)); } catch (SQLException e1) { log.println("Error: " + e1); } if(gotOne) { break; } else { synchronized(this) { // Add new connections to the pool if(currConnections < maxConns) { try { createConn(currConnections); currConnections++; } catch(SQLException e) { if(debugLevel > 0) { log.println("Error: Unable to create new connection: " + e); } } } } try { Thread.sleep(2000); } catch(InterruptedException e) {} if(debugLevel > 0) { log.println("-----> Connections Exhausted! Will wait and try again in loop " + String.valueOf(outerloop)); } } } // End of try 10 times loop } else { if(debugLevel > 0) { log.println("Unsuccessful getConnection() request during destroy()"); } } // End if(available) if(debugLevel > 2) { log.println("Handing out connection " + idOfConnection(conn) + " --> " + (new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a")).format(new java.util.Date())); }
return conn; } /** * Returns the local JDBC ID for a connection. */ public int idOfConnection(Connection conn) { int match; String tag; try { tag = conn.toString(); } catch (NullPointerException e1) { tag = "none"; } match=-1; for(int i=0; i< currConnections; i++) { if(connID.equals(tag)) { match = i; break; } } return match; } /** * Frees a connection. Replaces connection back into the main pool for * reuse. */ public String freeConnection(Connection conn) { String res=""; int thisconn = idOfConnection(conn); if(thisconn >= 0) { connStatus[thisconn]=0; res = "freed " + conn.toString(); //log.println("Freed connection " + String.valueOf(thisconn) + // " normal exit: "); } else { if(debugLevel > 0) { log.println("----> Error: Could not free connection!!!"); } } return res; } /** * Returns the age of a connection -- the time since it was handed out to * an application. */ public long getAge(Connection conn) { // Returns the age of the connection in millisec. int thisconn = idOfConnection(conn); return System.currentTimeMillis() - connLockTime[thisconn]; }
private void createConn(int i)
throws SQLException {
Date now = new Date(); try { Class.forName (dbDriver); connPool = DriverManager.getConnection (dbServer,dbLogin,dbPassword); connStatus=0; connID=connPool.toString(); connLockTime=0; connCreateDate = now.getTime(); } catch (ClassNotFoundException e2) { if(debugLevel > 0) { log.println("Error creating connection: " + e2); } } log.println(now.toString() + " Opening connection " + String.valueOf(i) + " " + connPool.toString() + ":"); } /** * Shuts down the housekeeping thread and closes all connections * in the pool. Call this method from the destroy() method of the servlet. */
/** * Multi-phase shutdown. having following sequence: * <OL> * <LI><code>getConnection()</code> will refuse to return connections. * <LI>The housekeeping thread is shut down.<br> * Up to the time of <code>millis</code> milliseconds after shutdown of * the housekeeping thread, <code>freeConnection()</code> can still be * called to return used connections. * <LI>After <code>millis</code> milliseconds after the shutdown of the * housekeeping thread, all connections in the pool are closed. * <LI>If any connections were in use while being closed then a * <code>SQLException</code> is thrown. * <LI>The log is closed. * </OL><br> * Call this method from a servlet destroy() method. * * @param millis the time to wait in milliseconds. * @exception SQLException if connections were in use after * <code>millis</code>. */ public void destroy(int millis) throws SQLException { // Checking for invalid negative arguments is not necessary, // Thread.join() does this already in runner.join().
// Stop issuing connections available=false;
// Shut down the background housekeeping thread runner.interrupt();
// Wait until the housekeeping thread has died. try { runner.join(millis); } catch(InterruptedException e){} // ignore // The housekeeping thread could still be running // (e.g. if millis is too small). This case is ignored. // At worst, this method will throw an exception with the // clear indication that the timeout was too short.
long startTime=System.currentTimeMillis();
// Wait for freeConnection() to return any connections // that are still used at this time. int useCount; while((useCount=getUseCount())>0 && System.currentTimeMillis() - startTime <= millis) { try { Thread.sleep(500); } catch(InterruptedException e) {} // ignore }
// Close all connections, whether safe or not for(int i=0; i < currConnections; i++) { try { connPool.close(); } catch (SQLException e1) { if(debugLevel > 0) { log.println("Cannot close connections on Destroy"); } } }
if(useCount > 0) { //bt-test successful String msg="Unsafe shutdown: Had to close "+useCount+ " active DB connections after "+millis+"ms"; log.println(msg); // Close all open files log.close(); // Throwing following Exception is essential because servlet authors // are likely to have their own error logging requirements. throw new SQLException(msg); }
// Close all open files log.close();
}//End destroy()
/** * Less safe shutdown. Uses default timeout value. * This method simply calls the <code>destroy()</code> method * with a <code>millis</code> * value of 10000 (10 seconds) and ignores <code>SQLException</code> * thrown by that method. * @see #destroy(int) */ public void destroy() { try { destroy(10000); } catch(SQLException e) {} }
/** * Returns the number of connections in use. */ // This method could be reduced to return a counter that is // maintained by all methods that update connStatus. // However, it is more efficient to do it this way because: // Updating the counter would put an additional burden on the most // frequently used methods; in comparison, this method is // rarely used (although essential). public int getUseCount() { int useCount=0; synchronized(connStatus) { for(int i=0; i < currConnections; i++) { if(connStatus > 0) { // In use useCount++; } } } return useCount; }//End getUseCount()
/** * Returns the number of connections in the dynamic pool. */ public int getSize() { return currConnections; }//End getSize()
}// End class
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年10月08日 09:54
|
回复
|
|
to wait4friend :
哦,这样的话,那你的程序明显有问题
wait()后没有notify()怎么行,这些是搭配使用的
我想你的意思可能是sleep()吧
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年10月08日 10:44
|
回复
|
|
|
wait(int)和sleep()是不是都可以呢?
|
|
|
|
|
|
Re: [寻]连接池例子
|
发表: 2002年10月08日 12:12
|
回复
|
|
应该是sleep(int)吧
wait我记得一定要和notifyAll()一起使用的
我线程写得也不多
我去查查先
|
|
|
|
|
|
这个主题有 18 回复 / 2 页 [
1 2
下一页
]
|
|
|