在开发有关数据库的应用时,虽然JDBC提供给我们许多便利,但在我们开发不同的应用的时候还是会重复着一些相同的工作,比如说编写数据库连接的程序,工作虽然不算多,但不断地重复实在是浪费时间,也增加了调试的复杂度;还有一点,我们应该尽量使用配置的数据源,笔者用的是Mysql,当用到中文应用上的时候Mysql的数据源没办法解决中文问题,另一方面又不希望每次都手动创建连接。基于以上遇到的两个小障碍,我编写了一个小框架,实现数据库使用方法最简单,能创建数据连接池。这些工作的实现都不需要再编程。
在Web应用中我们只需要在WEB-INF文件夹下面加入一个DBconfig.properties的文件,简单设置几个参数,再在Web.xml文件内加入一个listener元素即可。凡是JDBC支持的数据库类型都可以通过这两个文件来设置得到与数据库的连接。有了这个基础,开发者可以只需要考虑业务上的编程。比如说要实现什么样的查询和数据操作,开发者只需要定义这些业务上的方法即可。这样对开发效率来说大有改善。当然,如果在一些大的应用里面,用到ORM框架的话,这个框架就派不上用场了。这个小框架只适用于中小型的“利用关系数据库本土语言来工作”的应用。
使用的步骤:
一、配置DBconfig.properties
DBconfig.properties的设置例子如下:
url=jdbc:mysql://localhost:3306/article?useUnicode=true&characterEncoding=GB2312
user=dbuser
passWord=227711
DriverName=com.mysql.jdbc.Driver
maxConnections=10
url参数指定所要的数据库连接的URL。
user参数是连接该数据库的用户名
passWord参数是连接用户的密码
DriverName参数是所用数据库类型的驱动类
maxConnections可以设置最大连接数目
二、配置Web.xml:
在Web.xml中这样设置便可:
<web-app>
<listener>
<listener-class>bbmyth.util.dataBase.DataSourceProviderServlet</listener-class>
</listener>
</web-app>
不要去改变<listener>里面的所有东西。
三、用本应用包的API来编写业务程序
确保bbmyth.util.dataBase这个应用包在你的ClassPath(供编译程序用)中,或直接将该包Import入来。
最后定义自已的数据库操作Bean。注意这个Bean要继承bbmyth.util.dataBase.DBManager类,在这个DBManager类里提供了四个数据库操作变量:
Connection con:是连接类,框架已提供现成的连接,开发者可在程序里以下面的语句来获得数据库的连接:con=getConnection();
Statement smt:是查询语句类的变量,可直接使用;
PreparedStatement psmt:是预编译查询语句类的变量,可直接使用;
ResultSet rs:是结果集的变量,可直接使用。
每一次连接使用完之后,不管是用编译语句还是预编译语句和有没有返回结果集都可以直接用closeAll()函数来关闭它们,不推荐用他们自已的close()方法。
四、在Jsp中应用UseBean标签把该业务JavaBean应用进去,然后用SetProperty标签设置其一个参数。如:
<jsp:setProperty name="articledb" property="provider" value="<%=application.getAttribute("CONNECTOR")%>"/>
articledb是你自已的UseBean定义的Id。其他的不要改动。
五、调试运行!这样,就可以按照用户给的参数,自动在应用启动的时候创建所需要的连接池。在应用退出的时候释放连接。用Mysql在配置数据源因为总是加不了中文编码的参数,而在这里,可以直接在URL里加入中文参数。既实现了数据库连接的便利,又解决了中文连接的问题。
工作原理:
工作原理很简单:一个类实现了ServletContextListener的接口,可以实现Web应用的事件监听。我在应用的启动的时候读进配置文件的参数,然后按照参数连接数据库,把完成的连接存放到一个Bean当中,然后把这个Bean作为一个变量存放在ServletContext中即Jsp的Application范围中,整个应用都可以使用的。
接着,编写业务方法是用了该包里面的API,在Jsp页面里使用这个连接池实例的时候要通过UseBaen和SetProperty的标签来把ServletContext中的连接池变量作为参数用到自已的业务Bean来,这样就可以使用现成的连接池工作了。
另外,用户写业务Bean的时候继承DBManager类。该类已经定义好了一些必要的变量和实现了连接。用户可以直接开始写自已的业务逻辑方法。只须要知道要怎样开始,怎样结束就得了。
下面是该应用包的源代码:共有三个类文件,DataSourceProviderServlet .java在应用启动的时候生成连接存放到ConnectionProvider.java的类中。DBManager则是为编程提供便利的。
/*******************************************************************/
一、DataSourceProviderServlet .java
package bbmyth.util.dataBase;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContext;
import java.util.*;
import java.io.*;
import javax.sql.*;
import java.sql.*;
public class DataSourceProviderServlet implements ServletContextListener
{
public void contextDestroyed(ServletContextEvent sce)
{
/*本方法是在应用退出时由系统调用的,在这个时候我们
把所有的连接都关闭!*/
((ConnectionProvider)(sce.getServletContext().getAttribute("CONNECTOR"))).destroy();
sce.getServletContext().removeAttribute("CONNECTOR");
}
public void contextInitialized(ServletContextEvent sce)
{
/*本方法在应用初始时调用,这时我们可以创建连接并且存到
一个容器当中,存储在应用的上下文中,然后交由一个JavaBean
处理。*/
Properties ps=new Properties();
Vector connections=new Vector();
String url=null;
String user=null;
String passWord=null;
int maxConnections;
String DriverName=null;
ServletContext context=sce.getServletContext();
try
{
InputStream input=context
.getResourceAsStream("/WEB-INF/DBconfig.properties");
ps.load(input);
input.close();
url=(String)ps.get("url");
user=(String)ps.get("user");
passWord=(String)ps.get("passWord");
DriverName=(String)ps.get("DriverName");
maxConnections=Integer.parseInt(((String)ps.get("maxConnections")).trim(),10);
for(int i=0;i<maxConnections;i++)
{
connections.add(getConnection(url,user,passWord));
}
}
catch(Exception e)
{
e.printStackTrace();
}
context.setAttribute("CONNECTOR",new ConnectionProvider(connections));
}
public Connection getConnection(String url,String user,
String passWord)throws Exception
{
Class.forName(DriverName);
return DriverManager.getConnection(url,user,passWord);
}
}
二、ConnectionProvider.java
package bbmyth.util.dataBase;
import java.util.*;
import java.sql.*;
import javax.sql.*;
public class ConnectionProvider
{
private int maxConnections;
private Vector freeConnections;
private Vector nowConnections;
public ConnectionProvider(Vector connections)
{
freeConnections=new Vector();
nowConnections=new Vector();
freeConnections=connections;
maxConnections=freeConnections.size();
}
public Connection getConnection()
{
Connection temp=(Connection)freeConnections.firstElement();
freeConnections.remove(temp);
nowConnections.add(temp);
return temp;
}
public void closeConnection(Connection con)
{
/*Don't use the method close() provid by Connection to close the connection!
beacuase if you do that,the connection will not return to the pool!*/
nowConnections.remove(con);
freeConnections.add(con);
}
public void destroy()//can the container call this method?
{
freeConnections.removeAllElements();
nowConnections.removeAllElements();
}
}
三、DBManager.java
package bbmyth.util.dataBase;
import java.sql.*;
import javax.sql.*;
import java.util.*;
public class DBManager
{
protected ConnectionProvider provider=null;
protected Connection con=null;
protected Statement smt=null;
protected PreparedStatement psmt=null;
protected ResultSet rs=null;
public void setProvider(Object provider)
{
this.provider=(ConnectionProvider)provider;
}
public Connection getConnection()throws SQLException //get acess to database
{
if(provider==null)
throw new SQLException("missing the property 'provider'!!");
return provider.getConnection();
}
public void closeAll()
{
try
{
if(rs!=null)rs.close();
if(smt!=null)smt.close();
if(psmt!=null)psmt.close();
if(con!=null)provider.closeConnection(con);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
/**************************************************************************/
下面是一个应用的例子:该应用是一个文档的添加和查看的应用。在业务逻辑JavaBean里面只有三个方法
而这些方法是根据你自已的业务需要去添加和编写的。另外有一个代表了编文章的JavaBean。
一、ArticleDB.java
package article;
import java.sql.*;
import java.util.*;
import javax.naming.*;
import javax.sql.*;
import bbmyth.util.dataBase.*;
public class ArticleDB extends DBManager
{
public Article getArticleByTitle(String title)throws SQLException
{
Article article=new Article();
try
{
con=getConnection();
String sql="select * "+"from articles where title='"+title+"'";
smt=con.createStatement();
rs=smt.executeQuery(sql);
rs.next();
article.kind=rs.getString(1);
article.author=rs.getString(2);
article.title=rs.getString(3);
article.date=rs.getString(4);
article.body=rs.getString(5);
article.checknum=rs.getInt(6);
closeAll();
}
catch(Exception e)
{
e.printStackTrace();
}
return article;
}
public ArrayList executeQuery(String sql)throws SQLException
{
ArrayList list=new ArrayList();
try
{
con=this.getConnection();
smt=con.createStatement();
rs=smt.executeQuery(sql);
while(rs.next())
{
Article article =new Article();
article.kind=rs.getString(1);
article.author=rs.getString(2);
article.title=rs.getString(3);
article.date=rs.getString(4);
article.body=rs.getString(5);
article.checknum=rs.getInt(6);
list.add(article);
}
closeAll();
}
catch(SQLException e)
{
e.printStackTrace();
}
return list;
}
public void executeUpdate(String sql)throws SQLException
{
try
{
con=this.getConnection();
smt=con.createStatement();
smt.executeUpdate(sql);
closeAll();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
二、Article.java
package article;
import java.sql.*;
import java.util.*;
import javax.naming.*;
import javax.sql.*;
public class Article
{
String kind;
String author;
String title;
String date;
String body;
int checknum;
public Article()
{
}
public Article(String kind,String author,String title,String date,String body,int checknum)
{
this.kind=kind;
this.author=author;
this.title=title;
this.date=date;
this.body=body;
this.checknum=checknum;
}
/*********读取字段值********/
public int getChecknum()
{
return this.checknum;
}
public String getKind()
{
return this.kind;
}
public String getAuthor()
{
return this.author;
}
public String getTitle()
{
return this.title;
}
public String getDate()
{
return this.date;
}
public String getBody()
{
return this.body;
}
/**********设置字段值*********/
public void setKind(String kind)
{
this.kind=kind;
}
public void setAuthor(String author)
{
this.author=author;
}
public void setTitle(String title)
{
this.title=title;
}
public void setDate(String date)
{
this.date=date;
}
public void setBody(String body)
{
this.body=body;
}
public void setChecknum(int checknum)
{
this.checknum=checknum;
}
}
附:在Jsp中这样设置的:
<jsp:useBean id="articledb" class="article.ArticleDB" scope="application">
<jsp:setProperty name="articledb" property="provider" value="<%=application.getAttribute("CONNECTOR")%>"/>
</jsp:useBean>
这么一来,在Jsp中就可以随处使用你的业务Bean的方法来工作了。
总结:这是个很简单的小应用工具,适用于小型或中小型的应用。可以减少开发者在数据库连接上的花的工夫。专心编写业务程序。当然,也许很多人认为不必要,呵,这是我个人认为了。最好大家都能自已动手写一个,这样的话可以对数据库连接和相关的知识有更进一步的了解,另一方面可以方便自已以后的开发。数据池,最后不要用别人写的,要么自已写!写得不好没关系,再写!直接拿别人的来用就什么都学不到了。呵呵。我是这样认为的。这个工具到目前为止功能不算多,以后还会继续增加。