多年来,许多数据库技术已经问世,从而使得数据库访问变得更加有效和安全可靠。标准数据库能够支持索引、触发器、存储过程和事务管理等,JDBC能够支持所有这些特性。虽然DBHandle数据库组件没有支持上面所有的特性,但它给我们提供的是最常用、最有效的方法,提高了系统的开发和运行效率。
DBHandle数据库组件实现了部分JDBC的功能,如上面所介绍的用Class类建立数据库连接驱动;用DriverManager类实现数据库的连接;用Connection类中的createStatement方法获得对象;用prepareStatement方法获得可以预编译的对象;用Statement类的对象或PrepareStatement类定义的对象可以操作数据库或查询数据库,提供了对事务的操作功能。DBHandle数据库组件将这些操作都封装在一起,并将每个功能又封装在了不同的方法中,具体的功能将在下面做详细的介绍。
2.3.1 功能简介
除了连接数据库以外,DBHandle的主要功能还包括查询单条记录、查询记录个数、获得表对应的队列值、事务的操作、数据的回滚,以及事务的提交。含有事务的操作大大减少了系统读取脏数据或插入无效数据。在我们对数据库有两个以上操作时,被操作数据就会加锁。我们采用事务操作后的数据必须有提交操作才能提交给数据库。DBHandle区别于其他产品的一大优点是含有对多条记录的分页功能。
2.3.2 功能清单/组件参数
具体功能如表2-1所示:
表2-1 数据库组件具体功能
|
方 法 名 |
描 述 |
|
DBHandle() |
构造方法,初始化Connection和Statement |
|
输入 |
|
|
输出 |
|
|
getConnection() |
获得一个非Transaction数据库连接 |
|
输入 |
|
|
输出 |
return Connection 返回数据库的连接 |
|
getConnection(boolean transaction) |
获得一个Transaction的数据库连接 |
|
输入 |
true:为获得一个transaction的连接 false:为获得一个普通连接 |
|
输出 |
return Connection 返回数据库的连接 |
|
executeByConn(String sql) |
执行insert,update语句(此方法为static的方法) |
|
输入 |
insert,update的sql语句 |
|
输出 |
return true/false 返回成功/失败 |
|
getSingleValueByConn(String sql) |
获得数据库中某条记录值的方法(此方法为static的方法) |
|
输入 |
查询的sql语句 |
|
输出 |
return Object记录值 |
|
getCountValueByConn(String sql) |
获得记录个数的方法(此方法为static的方法) |
|
输入 |
查询的sql语句 |
|
输出 |
return int记录个数 |
|
getSequenceValueByConn(String sequence) |
获得表对应的Sequence值(此方法为static的方法) |
|
输入 |
sequence 表对应的sequence名 |
|
输出 |
return String Sequence值 |
|
execute(String sql) |
获得数据库的查询结果集 |
|
输入 |
查询的sql语句 |
|
输出 |
return Resultset 结果记录集 |
|
getSingleValue(String sql) |
获得数据库中某条记录值的方法 |
|
输入 |
查询的sql语句 |
|
输出 |
return Object记录值 |
续表
|
方 法 名 |
描 述 |
|
getCountValue(String sql) |
获得数据库中某条记录值的方法 |
|
输入 |
查询的SQL语句 |
|
输出 |
return Object记录值 |
|
getSequenceValue(String sequence) |
获得表对应的Sequence值 |
|
输入 |
sequence 表对应的sequence名 |
|
输出 |
return String Sequence值 |
|
executeQuery(String sql, int pageNum, int pageLines) |
获得分页结果集的方法 |
|
输入 |
sql为查询语句 pagenum为当前页 pageLine为每页显示条数 |
|
输出 |
return vector 返回分页后的集合 |
|
beginTransaction() |
获得一个回滚事务 |
|
输入 |
|
|
输出 |
|
|
commitExcute() |
执行操作,提交事务 |
|
输入 |
|
|
输出 |
|
|
rollBackExcute() |
回滚操作 |
|
输入 |
|
|
输出 |
|
|
close(ResultSet rset) |
关闭数据库结果集,数据库操作对象,数据库链接 |
|
输入 |
Resultset结果集 |
|
输出 |
|
|
close() |
数据库操作对象,数据库链接 |
|
输入 |
|
|
输出 |
|
|
getArrayByQuery(String sqlStr) |
将获得的所有记录记录放到一个二维数组中 |
|
输入 |
sqlStr为数据库查询语句 |
|
输出 |
return String[ ][ ] 返回所有查询结果的二维数组 |
|
getArrayByQuery(String sqlStr,int pageNum, int pageLines,int totalCount) |
先获得所有记录,再将这些数据进行分页后将分页的记录放到一个二维数组中 |
|
输入 |
sqlStr为数据库查询语句 pagenum为当前页 pageLines为每页显示条数 totaleCount为记录总数 |
|
输出 |
return String[ ][ ] 返回分页后每页的集合的二维数组 |
在组件中的静态方法是可以直接采用类名点方法名的形式添加,因为在这些静态方法中含有了对数据库的开关操作。在非静态的方法中,必须初始化DBHandle类的对象,因为在DBHandle类的构造方法中,初始化了数据库的连接和数据库的操作对象。
2.3.3 示例代码解析
下面通过实例代码详细说明如何实现对数据库的操作。在对数据库的操作中我们用到了一个数据库,用户可以使用任何DBMS自己建一个数据库。
下面先对这个数据库结构做一下介绍。
在Oracle数据库中创建表“Book_Info”,其字段如表2-2所示:
表2-2 数据表结构
|
字 段 名 |
类 型 |
长 度 |
说 明 |
|
Auto_ID |
Integer |
8 |
自增变量,需与Sequnce 绑定 |
|
Title |
Text |
30 |
必填 |
|
Author |
Text |
10 |
必填 |
|
Press |
Text |
30 |
必填 |
|
PublishDate |
Date |
8 |
|
|
Price |
Number |
8.2 |
|
为了方便用户了解数据库访问组件的使用功能,下面将向您介绍实例代码的调用过程以及对实例代码的详细解析。
首先向您介绍一下实例代码的使用步骤。
首先建一个上面所说的数据库。
在Eclips中建一个Web工程,在工程下面建一个smart.css.database包。
将所用到的组件考到第二步所建的包下面。
然后建一个JSP,将实例代码复制到JSP页面中。
在Eclips中开启Tomcat。
在IE浏览器中输入网页地址,就可以看到执行的结果。
(a)下面是不需要初始化对象的实例代码,所谓不需要初始化实例是因为在这些方法体里已经有开关数据库的操作,不需要通过初始化实例来开关数据库。
<%@ page language="java" import="java.sql.*,java.util.*" pageEncoding="utf-8"%>
<%
String executesql = "insert into testbook values(testbook_seq.nextval,'java核心思想','王建华','机械工业出版社',to_date('2009-06-05','yyyy-mm-dd'),12)";
String singlesql = "select title from testbook";
String countsql = "select * from testbook";
String executeQuerysql = "select title from testbook where auto_id='269'";
try
{
//操作数据库,直接调用方法
boolean bl = DBHandle.executeByConn(executesql);
//在后台显示方法的返回值结果
System.out.println(bl);
//得到单条记录的数值
Object single = DBHandle.getSingleValueByConn(singlesql);
System.out.println(single.toString());
//计算记录条数
int count = DBHandle.getCountValueByConn(countsql);
System.out.println(count);
//得到下一个要添加的序列号
String sequence = DBHandle.getSequenceValueByConn("testbook_seq");
System.out.println(sequence);
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
%>
(b)下面是必须初始化对象的实例,“必须”是因为这些方法都是普通的公有方法,必须通过对象调用,且在方法体中没有关闭数据库的操作,所以我们必须手动地在finally中关闭数据库。
<%@ page language="java" import="java.sql.*,java.util.*" pageEncoding="utf-8"%>
<%
String executesql = "insert into testbook values(testbook_seq.nextval,'java核心思想','王建华','机械工业出版社',to_date('2009-06-05','yyyy-mm-dd'),12)";
String singlesql = "select title from testbook";
String countsql = "select * from testbook";
String executeQuerysql = "select title from testbook where auto_id='269'";
DBHandle dbh = new DBHandle();
//以下方法是在构造方法里开启数据库的,且要在finally中关闭数据库
try
{
boolean blValue = dbh.execute(executesql);
//输出方法返回值
System.out.println(blValue);
//查询数据库,返回结果值。
ResultSet rs = dbh.executeQuery(executeQuerysql);
if(rs.next())
{
String querystr = rs.toString();
System.out.println(querystr);
}
//返回单条记录的值
Object singleValue = dbh.getSingleValue(singlesql);
System.out.println(singleValue.toString());
//返回记录的条数
int countValue = dbh.getCountValue(countsql);
System.out.println(countValue);
//返回队列值
String sequenceValue = dbh.getSequenceValue("testbook_seq");
System.out.println(sequenceValue);
//用于分页显示,1表示当前页,2表示每页显示条数
Vector vec = dbh.executeQuery(countsql,1,2);
for(int i=0;i<vec.size();i++)
{
for(int j=0;j<6;j++)
{
System.out.println(((Vector)vec.elementAt(i)).elementAt(j).toString());
}
}
//返回分页前的结果,保存在二维数组中
String[ ][ ] arr = dbh.getArrayByQuery(countsql);
}
catch(Exception e)
{
e.getMessage();
}
finally
{
try {
//关闭数据库的操作
dbh.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
%>
第一种实例给那些经常忘记关闭数据库的人提供了方便,但是如果对数据库的操作需要应用在循环当中,第一种方法的效率会很低,耗时会很长,因为开关数据库是消耗内存很大的工程,特别是建立连接。在这种情况下,我们会选择第二种方法,但是要提醒用户一定要在最后关闭数据库,否则适得其反。
2.3.4 源码解析
下面针对DBHandle类的源码进行解析,以方便用户理解。在这里使用的是Oracle数据库,当然用户也可以使用其他任何一种数据库,有关其他数据库的驱动和URL将在本章小结中给出详细的说明。
在这里还用到了时间的操作组件DateUtils,在后续章节中有详细的介绍。
/**
* 构造函数,注意构造时给初始化了Connection和Statement。
*/
public DBHandle() {
try {
conn = getConnection();
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_ UPDATABLE);
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* 执行操作:执行insert 和 update语句,在方法内初始化了数据库连接
* @param sql:SQL语句
* @return 执行的条数
* @throws SQLException
* @throws Exception
*/
public static boolean executeByConn(String sql) throws SQLException,Exception{
boolean result=false;
Connection conn = null;
//PreparedStatement stmt = null;
Statement stmt = null;
try {
conn = getConnection();
stmt=conn.createStatement();
int executeCount=stmt.executeUpdate(sql);
if (executeCount>0){
result=true;
}
//stmt = conn.prepareStatement(sql);
//result = stmt.execute();
}catch (SQLException e){
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}finally {
if(stmt != null){
stmt.close();
stmt = null;
}
if(conn != null){
conn.close();
conn= null;
}
}
return result;
}
/**
* 获得数据库中某单个字段的值,在方法内初始化了数据库连接
* @param sql:SQL查询语句
* @return:Object对象,需要转化成对应类型才可以使用。
* @throws Exception
*/
public static Object getSingleValueByConn(String sql) throws Exception{
Object value=null;
ResultSet rs=null;
Connection conn = null;
Statement stmt = null;
try {
conn = getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
if (rs.next()) {
value = rs.getObject(1);
}
}catch(SQLException se){
}catch(Exception ex){
}finally {
if(rs != null){
rs.close();
rs = null;
}
if(stmt != null){
stmt.close();
stmt = null;
}
if(conn != null){
conn.close();
conn = null;
}
}
return value;
}
/**
@ 获得查询语句查询结果的个数,在方法内初始化了数据库连接
@ Param: SQL
@ Exception: SQLException
@ return int:count
**/
public static int getCountValueByConn(String sql) throws SQLException,Exception {
int countOfQuery=0;
Statement stmt=null;
Connection conn = null;
ResultSet rs = null;
try {
conn = getConnection();
stmt = conn.createStatement();
sql = "SELECT COUNT(*) AS count_of_query FROM ("+sql+")";
rs = stmt.executeQuery(sql);
if (rs.next()) {
countOfQuery=rs.getInt("count_of_query");
}
}catch(SQLException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}finally {
if (rs!=null) {
rs.close();
rs = null;
}
if(stmt != null){
stmt.close();
stmt = null;
}
if(conn != null){
conn.close();
conn = null;
}
}
return countOfQuery;
}
/**
@ 从某个Sequence队列中取一个值,在方法内初始化了数据库链接
@ Param: sequence:Sequeence的名称
@ Exception: SQLException
@ return int:count
**/
public static String getSequenceValueByConn(String sequence) throws SQLException,Exception {
String valueOfSequence="";
Statement stmt=null;
Connection conn = null;
ResultSet rs = null;
try {
conn = getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select"+sequence+".nextval as value_of_sequence from dual");
if (rs.next()) {
valueOfSequence=rs.getString("value_of_sequence");
}
}catch(SQLException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}finally {
if (rs!=null) {
rs.close();
rs = null;
}
if(stmt != null){
stmt.close();
stmt = null;
}
if(conn != null){
conn.close();
conn = null;
}
}
return valueOfSequence;
}
/**
* 查询语句。执行select命令
* @param sql \u00CA\u00FD\u00BE\u00DD\u00BF\u00E2SQL\u00D3\u00EF\u00BE\u00E4
* @exception SQLException,Exception
* @return ResultSet
*/
public ResultSet executeQuery(String sql) throws SQLException, Exception {
ResultSet rs = null;
try {
rs = stmt.executeQuery(sql);
}
catch (SQLException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return rs;
}
/**
* 执行操作:执行insert 和 update语句
* @param sql:SQL语句
* @return 执行的条数
* @throws SQLException
* @throws Exception
*/
public boolean execute(String sql) throws SQLException, Exception {
boolean result = false;
Connection conn = null;
//PreparedStatement stmt = null;
Statement stmt = null;
try {
conn = this.conn;
stmt = this.stmt;
int executeCount = stmt.executeUpdate(sql);
if (executeCount >=0) {
result = true;
}
//stmt = conn.prepareStatement(sql);
//result = stmt.execute();
}
catch (SQLException e) {
e.printStackTrace();
result=false;
}
catch (Exception e) {
e.printStackTrace();
result=false;
}
return result;
}
/**
* 获得数据库中某个单个字段的值
* @param sql:SQL查询语句
* @return :Object对象,需要转化成对应类型才可以使用。
* @throws Exception
*/
public Object getSingleValue(String sql) throws Exception {
Object value = null;
ResultSet rs = null;
Connection conn = null;
Statement stmt = null;
try {
conn = this.conn;
stmt = this.stmt;
rs = stmt.executeQuery(sql);
if (rs.next()) {
value = rs.getObject(1);
}
}
catch (SQLException se) {
se.printStackTrace();
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
if (rs != null) {
rs.close();
rs = null;
}
}
return value;
}
/**
@ 获得查询语句查询结果的个数.
@ Param: SQL
@ Exception: SQLException
@ return int:count
**/
public int getCountValue(String sql) throws SQLException, Exception {
int countOfQuery = 0;
Statement stmt = null;
Connection conn = null;
ResultSet rs = null;
try {
conn = this.conn;
stmt = this.stmt;
sql = "SELECT COUNT(*) AS count_of_query FROM (" + sql + ")";
rs = stmt.executeQuery(sql);
if (rs.next()) {
countOfQuery = rs.getInt("count_of_query");
}
}
catch (SQLException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (rs != null) {
rs.close();
rs = null;
}
}
return countOfQuery;
}
/**
@ 从某个Sequence队列中取一个值
@ Param: sequence:Sequeence的名称
@ Exception: SQLException
@ return int:count
**/
public String getSequenceValue(String sequence) throws SQLException,
Exception {
String valueOfSequence = "";
Statement stmt = null;
Connection conn = null;
ResultSet rs = null;
try {
conn = this.conn;
stmt = this.stmt;
rs = stmt.executeQuery("select " + sequence +
".nextval as value_of_sequence from dual");
if (rs.next()) {
valueOfSequence = rs.getString("value_of_sequence");
}
}
catch (SQLException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (rs != null) {
rs.close();
rs = null;
}
}
return valueOfSequence;
}
/**
*关闭数据库操作对象与数据库连接对象
* Close all the statement and conn int this instance
* @throws SQLException
* @throws Exception
*/
public void close() throws SQLException, Exception {
if (stmt != null) {
stmt.close();
stmt = null;
}
if (conn != null) {
conn.close();
conn = null;
}
}
上面的源码中不仅含有普通的数据库连接,也含有数据库连接池的使用方法。应用数据库连接池对于开关数据库频繁的操作来说是非常有必要的。前面我们提到过建立和销毁数据库的连接都是非常耗费时间和空间的,而数据库连接池会将最大保持连接数放在池中,它会等待有数据库的操作出现。且一个数据库操作结束后也不会立即销毁这个连接,在最大等待时间内如果有数据库的操作,就不需要再次建立连接了。所以对于操作数据库频繁的程序使用这种连接是可以节省时间和空间的。





