当前位置: 技术问答>java相关
高分求数据库(SQL-Server 2000)连接池!!!!
来源: 互联网 发布时间:2015-06-20
本文导语: 高分求数据库连接池,最后有注释说明,详细一点;谢谢! | 一、数据库连接池类 DBConnectionPool,提供如下的方法: 1、从池中取得一个打开的连接; 2、将一个连接返回池中; ...
高分求数据库连接池,最后有注释说明,详细一点;谢谢!
|
一、数据库连接池类 DBConnectionPool,提供如下的方法:
1、从池中取得一个打开的连接;
2、将一个连接返回池中;
3、在关闭时释放所有的资源,并关闭所有的连接。
另外,DBConnectionPool还处理连接失败,比如超时,通讯失败等错误,并且根据预定义的参数限制池中的连接数。
二、管理者类,DBConnetionManager,是一个容器将连接池封装在内,并管理所有的连接池。它的方法有:
1、 调用和注册所有的jdbc驱动程序;
2、 根据参数表创建DBConnectionPool对象;
3、 映射连接池的名字和DBConnectionPool实例;
4、 当所有的连接客户退出后,关闭全部连接池。
这些类的实现,以及如何在servlet中使用连接池的应用在随后的文章中讲解
DBConnectionPool类代表一个由url标识的数据库连接池。前面,我们已经提到,jdbc的url由三个部分组成:协议标识(总是jdbc),子协议标识(例如,odbc.oracle),和数据库标识(跟特定的数据库有关)。连接池也具有一个名字,供客户程序引用。另外,连接池还有一个用户名,一个密码和一个最大允许连接数。如果web应用允许所有的用户使用某些数据库操作,而另一些操作是有限制的,则可以创建两个连接池,具有同样的url,不同的user name和password,分别处理两类不同的操作权限。现把DBConnectionPool详细介绍如下:
一、DBConnectionPool的构造
构造函数取得上述的所有参数:
public DBConnectionPool(String name, String URL, String user,
String password, int maxConn) {
this.name = name;
this.URL = URL;
this.user = user;
this.password = password;
this.maxConn = maxConn;
}
将所有的参数保存在实例变量中。
二、从池中打开一个连接
DBConnectionPool提供两种方法来检查连接。两种方法都返回一个可用的连接,如果没有多余的连接,则创建一个新的连接。如果最大连接数已经达到,第一个方法返回null,第二个方法则等待一个连接被其他进程释放。
public synchronized Connection getConnection() {
Connection con = null;
if (freeConnections.size() > 0) {
// Pick the first Connection in the Vector
// to get round-robin usage
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
if (con.isClosed()) {
log("Removed bad connection from " + name);
// Try again recursively
con = getConnection();
}
}
catch (SQLException e) {
log("Removed bad connection from " + name);
// Try again recursively
con = getConnection();
}
}
else if (maxConn == 0 || checkedOut = timeout) {
// Timeout has expired
return null;
}
}
return con;
}
局部变量startTime初始化当前的时间。一个while循环首先尝试获得一个连接,如果失败,wait()函数被调用来等待需要的时间。后面会看到,Wait()函数会在另一个进程调用notify()或者notifyAll()时返回,或者等到时间流逝完毕。为了确定wait()是因为何种原因返回,我们用开始时间减去当前时间,检查是否大于timeout。如果结果大于timeout,返回null,否则,在此调用getConnection()函数。
1、从池中取得一个打开的连接;
2、将一个连接返回池中;
3、在关闭时释放所有的资源,并关闭所有的连接。
另外,DBConnectionPool还处理连接失败,比如超时,通讯失败等错误,并且根据预定义的参数限制池中的连接数。
二、管理者类,DBConnetionManager,是一个容器将连接池封装在内,并管理所有的连接池。它的方法有:
1、 调用和注册所有的jdbc驱动程序;
2、 根据参数表创建DBConnectionPool对象;
3、 映射连接池的名字和DBConnectionPool实例;
4、 当所有的连接客户退出后,关闭全部连接池。
这些类的实现,以及如何在servlet中使用连接池的应用在随后的文章中讲解
DBConnectionPool类代表一个由url标识的数据库连接池。前面,我们已经提到,jdbc的url由三个部分组成:协议标识(总是jdbc),子协议标识(例如,odbc.oracle),和数据库标识(跟特定的数据库有关)。连接池也具有一个名字,供客户程序引用。另外,连接池还有一个用户名,一个密码和一个最大允许连接数。如果web应用允许所有的用户使用某些数据库操作,而另一些操作是有限制的,则可以创建两个连接池,具有同样的url,不同的user name和password,分别处理两类不同的操作权限。现把DBConnectionPool详细介绍如下:
一、DBConnectionPool的构造
构造函数取得上述的所有参数:
public DBConnectionPool(String name, String URL, String user,
String password, int maxConn) {
this.name = name;
this.URL = URL;
this.user = user;
this.password = password;
this.maxConn = maxConn;
}
将所有的参数保存在实例变量中。
二、从池中打开一个连接
DBConnectionPool提供两种方法来检查连接。两种方法都返回一个可用的连接,如果没有多余的连接,则创建一个新的连接。如果最大连接数已经达到,第一个方法返回null,第二个方法则等待一个连接被其他进程释放。
public synchronized Connection getConnection() {
Connection con = null;
if (freeConnections.size() > 0) {
// Pick the first Connection in the Vector
// to get round-robin usage
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
if (con.isClosed()) {
log("Removed bad connection from " + name);
// Try again recursively
con = getConnection();
}
}
catch (SQLException e) {
log("Removed bad connection from " + name);
// Try again recursively
con = getConnection();
}
}
else if (maxConn == 0 || checkedOut = timeout) {
// Timeout has expired
return null;
}
}
return con;
}
局部变量startTime初始化当前的时间。一个while循环首先尝试获得一个连接,如果失败,wait()函数被调用来等待需要的时间。后面会看到,Wait()函数会在另一个进程调用notify()或者notifyAll()时返回,或者等到时间流逝完毕。为了确定wait()是因为何种原因返回,我们用开始时间减去当前时间,检查是否大于timeout。如果结果大于timeout,返回null,否则,在此调用getConnection()函数。
|
四、将一个连接返回池中
DBConnectionPool类中有一个freeConnection方法以返回的连接作为参数,将连接返回连接池。
public synchronized void freeConnection(Connection con) {
// Put the connection at the end of the Vector
freeConnections.addElement(con);
checkedOut--;
notifyAll();
}
连接被加在freeConnections向量的最后,占用的连接数减1,调用notifyAll()函数通知其他等待的客户现在有了一个连接。
五、关闭
大多数servlet引擎提供完整的关闭方法。数据库连接池需要得到通知以正确地关闭所有的连接。DBConnectionManager负责协调关闭事件,但连接由各个连接池自己负责关闭。方法relase()由DBConnectionManager调用。
public synchronized void release() {
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection con = (Connection) allConnections.nextElement();
try {
con.close();
log("Closed connection for pool " + name);
}
catch (SQLException e) {
log(e, "Can not close connection for pool " + name);
}
}
freeConnections.removeAllElements();
}
本方法遍历freeConnections向量以关闭所有的连接。
DBConnetionManager的构造函数是私有函数,以避免其他类创建其实例。
private DBConnectionManager() {
init();
}
DBConnetionManager的客户调用getInstance()方法来得到该类的单一实例的引用。
static synchronized public DBConnectionManager getInstance() {
if (instance == null) {
instance = new DBConnectionManager();
}
clients++;
return instance;
}
单一的实例在第一次调用时创建,以后的调用返回该实例的静态应用。一个计数器纪录所有的客户数,直到客户释放引用。这个计数器在以后用来协调关闭连接池。
一、初始化
构造函数调用一个私有的init()函数初始化对象。
private void init() {
InputStream is = getClass().getResourceAsStream("/db.properties");
Properties dbProps = new Properties();
try {
dbProps.load(is);
}
catch (Exception e) {
System.err.println("Can not read the properties file. " +
"Make sure db.properties is in the CLASSPATH");
return;
}
String logFile = dbProps.getProperty("logfile",
"DBConnectionManager.log");
try {
log = new PrintWriter(new FileWriter(logFile, true), true);
}
catch (IOException e) {
System.err.println("Can not open the log file: " + logFile);
log = new PrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
}
方法getResourceAsStream()是一个标准方法,用来打开一个外部输入文件。文件的位置取决于类加载器,而标准的类加载器从classpath开始搜索。Db.properties文件是一个Porperties格式的文件,保存在连接池中定义的key-value对。下面一些常用的属性可以定义:
drivers 以空格分开的jdbc驱动程序的列表
logfile 日志文件的绝对路径
每个连接池中还使用另一些属性。这些属性以连接池的名字开头:
.url数据库的JDBC URL
.maxconn最大连接数。0表示无限。
.user连接池的用户名
.password相关的密码
url属性是必须的,其他属性可选。用户名和密码必须和所定义的数据库匹配。
下面是windows平台下的一个db.properties文件的例子。有一个InstantDB连接池和一个通过odbc连接的access数据库的数据源,名字叫demo。
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver
logfile=D:\user\src\java\DBConnectionManager\log.txt
idb.url=jdbc:idb:c:\local\javawebserver1.1\db\db.prp
idb.maxconn=2
access.url=jdbc:odbc:demo
access.user=demo
access.password=demopw
注意,反斜线在windows平台下必须双写。
DBConnectionPool类中有一个freeConnection方法以返回的连接作为参数,将连接返回连接池。
public synchronized void freeConnection(Connection con) {
// Put the connection at the end of the Vector
freeConnections.addElement(con);
checkedOut--;
notifyAll();
}
连接被加在freeConnections向量的最后,占用的连接数减1,调用notifyAll()函数通知其他等待的客户现在有了一个连接。
五、关闭
大多数servlet引擎提供完整的关闭方法。数据库连接池需要得到通知以正确地关闭所有的连接。DBConnectionManager负责协调关闭事件,但连接由各个连接池自己负责关闭。方法relase()由DBConnectionManager调用。
public synchronized void release() {
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection con = (Connection) allConnections.nextElement();
try {
con.close();
log("Closed connection for pool " + name);
}
catch (SQLException e) {
log(e, "Can not close connection for pool " + name);
}
}
freeConnections.removeAllElements();
}
本方法遍历freeConnections向量以关闭所有的连接。
DBConnetionManager的构造函数是私有函数,以避免其他类创建其实例。
private DBConnectionManager() {
init();
}
DBConnetionManager的客户调用getInstance()方法来得到该类的单一实例的引用。
static synchronized public DBConnectionManager getInstance() {
if (instance == null) {
instance = new DBConnectionManager();
}
clients++;
return instance;
}
单一的实例在第一次调用时创建,以后的调用返回该实例的静态应用。一个计数器纪录所有的客户数,直到客户释放引用。这个计数器在以后用来协调关闭连接池。
一、初始化
构造函数调用一个私有的init()函数初始化对象。
private void init() {
InputStream is = getClass().getResourceAsStream("/db.properties");
Properties dbProps = new Properties();
try {
dbProps.load(is);
}
catch (Exception e) {
System.err.println("Can not read the properties file. " +
"Make sure db.properties is in the CLASSPATH");
return;
}
String logFile = dbProps.getProperty("logfile",
"DBConnectionManager.log");
try {
log = new PrintWriter(new FileWriter(logFile, true), true);
}
catch (IOException e) {
System.err.println("Can not open the log file: " + logFile);
log = new PrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
}
方法getResourceAsStream()是一个标准方法,用来打开一个外部输入文件。文件的位置取决于类加载器,而标准的类加载器从classpath开始搜索。Db.properties文件是一个Porperties格式的文件,保存在连接池中定义的key-value对。下面一些常用的属性可以定义:
drivers 以空格分开的jdbc驱动程序的列表
logfile 日志文件的绝对路径
每个连接池中还使用另一些属性。这些属性以连接池的名字开头:
.url数据库的JDBC URL
.maxconn最大连接数。0表示无限。
.user连接池的用户名
.password相关的密码
url属性是必须的,其他属性可选。用户名和密码必须和所定义的数据库匹配。
下面是windows平台下的一个db.properties文件的例子。有一个InstantDB连接池和一个通过odbc连接的access数据库的数据源,名字叫demo。
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver
logfile=D:\user\src\java\DBConnectionManager\log.txt
idb.url=jdbc:idb:c:\local\javawebserver1.1\db\db.prp
idb.maxconn=2
access.url=jdbc:odbc:demo
access.user=demo
access.password=demopw
注意,反斜线在windows平台下必须双写。
|
初始化方法init()创建一个Porperties对象并装载db.properties文件,然后读取日志文件属性。如果日志文件没有命名,则使用缺省的名字DBConnectionManager.log在当前目录下创建。在此情况下,一个系统错误被纪录。
方法loadDrivers()将指定的所有jdbc驱动程序注册,装载。
private void loadDrivers(Properties props) {
String driverClasses = props.getProperty("drivers");
StringTokenizer st = new StringTokenizer(driverClasses);
while (st.hasMoreElements()) {
String driverClassName = st.nextToken().trim();
try {
Driver driver = (Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
log("Registered JDBC driver " + driverClassName);
}
catch (Exception e) {
log("Can not register JDBC driver: " +
driverClassName + ", Exception: " + e);
}
}
}
loadDrivers()使用StringTokenizer将dirvers属性分成单独的driver串,并将每个驱动程序装入java虚拟机。驱动程序的实例在JDBC 的DriverManager中注册,并加入一个私有的向量drivers中。向量drivers用来关闭和注销所有的驱动程序。
然后,DBConnectionPool对象由私有方法createPools()创建。
private void createPools(Properties props) {
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
if (name.endsWith(".url")) {
String poolName = name.substring(0, name.lastIndexOf("."));
String url = props.getProperty(poolName + ".url");
if (url == null) {
log("No URL specified for " + poolName);
continue;
}
String user = props.getProperty(poolName + ".user");
String password = props.getProperty(poolName + ".password");
String maxconn = props.getProperty(poolName + ".maxconn", "0");
int max;
try {
max = Integer.valueOf(maxconn).intValue();
}
catch (NumberFormatException e) {
log("Invalid maxconn value " + maxconn + " for " +
poolName);
max = 0;
}
DBConnectionPool pool =
new DBConnectionPool(poolName, url, user, password, max);
pools.put(poolName, pool);
log("Initialized pool " + poolName);
}
}
}
一个枚举对象保存所有的属性名,如果属性名带有.url结尾,则表示是一个连接池对象需要被实例化。创建的连接池对象保存在一个Hashtable实例变量中。连接池名字作为索引,连接池对象作为值
现在我们结合DBConnetionManager和DBConnectionPool类来讲解servlet中连接池的使用:
一、首先简单介绍一下Servlet的生命周期:
Servlet API定义的servlet生命周期如下:
1、 Servlet 被创建然后初始化(init()方法)。
2、 为0个或多个客户调用提供服务(service()方法)。
3、 Servlet被销毁,内存被回收(destroy()方法)。
二、servlet中使用连接池的实例
使用连接池的servlet有三个阶段的典型表现是:
1. 在init()中,调用DBConnectionManager.getInstance()然后将返回的引用保存在实例变量中。
2. 在sevice()中,调用getConnection(),执行一系列数据库操作,然后调用freeConnection()归还连接。
3. 在destroy()中,调用release()来释放所有的资源,并关闭所有的连接。
下面的例子演示如何使用连接池。
import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
private DBConnectionManager connMgr;
public void init(ServletConfig conf) throws ServletException {
super.init(conf);
connMgr = DBConnectionManager.getInstance();
}
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
Connection con = connMgr.getConnection("idb");
if (con == null) {
out.println("Cant get connection");
return;
}
ResultSet rs = null;
ResultSetMetaData md = null;
Statement stmt = null;
try {
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
md = rs.getMetaData();
out.println("
Employee data
");
while (rs.next()) {
out.println("
");
for (int i = 1; i
方法loadDrivers()将指定的所有jdbc驱动程序注册,装载。
private void loadDrivers(Properties props) {
String driverClasses = props.getProperty("drivers");
StringTokenizer st = new StringTokenizer(driverClasses);
while (st.hasMoreElements()) {
String driverClassName = st.nextToken().trim();
try {
Driver driver = (Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
log("Registered JDBC driver " + driverClassName);
}
catch (Exception e) {
log("Can not register JDBC driver: " +
driverClassName + ", Exception: " + e);
}
}
}
loadDrivers()使用StringTokenizer将dirvers属性分成单独的driver串,并将每个驱动程序装入java虚拟机。驱动程序的实例在JDBC 的DriverManager中注册,并加入一个私有的向量drivers中。向量drivers用来关闭和注销所有的驱动程序。
然后,DBConnectionPool对象由私有方法createPools()创建。
private void createPools(Properties props) {
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
if (name.endsWith(".url")) {
String poolName = name.substring(0, name.lastIndexOf("."));
String url = props.getProperty(poolName + ".url");
if (url == null) {
log("No URL specified for " + poolName);
continue;
}
String user = props.getProperty(poolName + ".user");
String password = props.getProperty(poolName + ".password");
String maxconn = props.getProperty(poolName + ".maxconn", "0");
int max;
try {
max = Integer.valueOf(maxconn).intValue();
}
catch (NumberFormatException e) {
log("Invalid maxconn value " + maxconn + " for " +
poolName);
max = 0;
}
DBConnectionPool pool =
new DBConnectionPool(poolName, url, user, password, max);
pools.put(poolName, pool);
log("Initialized pool " + poolName);
}
}
}
一个枚举对象保存所有的属性名,如果属性名带有.url结尾,则表示是一个连接池对象需要被实例化。创建的连接池对象保存在一个Hashtable实例变量中。连接池名字作为索引,连接池对象作为值
现在我们结合DBConnetionManager和DBConnectionPool类来讲解servlet中连接池的使用:
一、首先简单介绍一下Servlet的生命周期:
Servlet API定义的servlet生命周期如下:
1、 Servlet 被创建然后初始化(init()方法)。
2、 为0个或多个客户调用提供服务(service()方法)。
3、 Servlet被销毁,内存被回收(destroy()方法)。
二、servlet中使用连接池的实例
使用连接池的servlet有三个阶段的典型表现是:
1. 在init()中,调用DBConnectionManager.getInstance()然后将返回的引用保存在实例变量中。
2. 在sevice()中,调用getConnection(),执行一系列数据库操作,然后调用freeConnection()归还连接。
3. 在destroy()中,调用release()来释放所有的资源,并关闭所有的连接。
下面的例子演示如何使用连接池。
import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
private DBConnectionManager connMgr;
public void init(ServletConfig conf) throws ServletException {
super.init(conf);
connMgr = DBConnectionManager.getInstance();
}
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
Connection con = connMgr.getConnection("idb");
if (con == null) {
out.println("Cant get connection");
return;
}
ResultSet rs = null;
ResultSetMetaData md = null;
Statement stmt = null;
try {
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
md = rs.getMetaData();
out.println("
Employee data
");
while (rs.next()) {
out.println("
");
for (int i = 1; i