您的位置:首页 > 数据库

设计模式在Java数据库编程中的运用

2006-04-23 18:07 281 查看
JDBC技术是Java语言中数据库编程的标准,近年来随着B/S应用的广泛兴起,Java技术在目前的服务器端越来越受重用。作为信息系统中关键的一部分,数据库编程是编程人员必须掌握的一部分。JDBC技术本身提供了一些可用的编程接口来完成一些基础事务的处理,但我们也发现,如果只是单纯地使用JDBC规范中提供的编程接口来完成事务逻辑的话,代码的冗余度十分高,编程效率也很低。基于此,如果在底层接口的基础之上,运用适当的设计模式进行抽象封装,并加以一些特定的设计以后,就会在JDBC规范接口之上形成一个可扩展的框架。在这个抽象层次上进行开发,不论是重用性、可靠性,还是开发效率,都会大大提高。
1.设计模式要点
所谓模式,就是对特定情形下特定问题的解决方案。这些方案,往往是经验的总结,是公认优秀的。设计模式就是在面向对象软件设计时对特定场景下特定问题的公认优秀的设计方案。面向对象思想出现这么多年,现在已经有了好多特定的模式值得我们在设计软件时遇到大多数问题时参考借鉴。
2.JDBC编程的要点
利用JDBC标准提供的接口,如果要进行数据库的访问,一般的编程过程如下:
(1)获取数据库的连接。
(2)对取得的连接的进行特定SQL语句的操作。
如果每次对数据库访问都单单进行以上的操作过程,而不进行一定的组织设计,那么代码的冗余度将会十分高,程序员的工作量也十分大,并且编写出来的代码也很不灵活,因此有必要引入一定的设计模式来提高代码的可复用度与可扩展性。
3.利用Factory Method模式控制数据库连接的产生
在实际的已经确定的系统中,数据库往往是很少变化的,所以获取数据库的第一步在几乎所有的访问中都是相同的,为了提高复用度,有必要把它提取成一个单独的模块。在这里,只可以使用Factory Method来封装产生数据库连接操作。考虑到连接的频繁性,没有必要每次要求访问数据库都对数据库申请产生连接,我们可以使用连接池技术来管理一定数量的数据库连接,这里我们定义一个ConnectionPool类,其产生数据库连接的操作定义为newConnection()。
以下是Factory Method基本的代码片断:
public class ConnectionPool……
private Connection newConnection() {
……
Connection con = DriverManager.getConnection(URL, user, password);
……
return con;
  }
4.利用Singleton模式来控制连接池对象的惟一性
我们已经有了管理数据库连接的连接池类ConnectionPool,但要注意一点:连接池对象在系统运行时应该是惟一的。原因很简单,如果不惟一的话,对不同的数据库访问产生不同的连接池对象,那么连接池对象的作用就根本没有起。当然,也可以在程序中只创建一个连接池对象,但这不能保证别的程序员也能做到这一点,这时,应该采用singleton模式,通过getInstance()方法获取惟一的连接池对象。
public class ConnectionPool……
public class ConnectionPool {
  private static ConnectionPool instance = null;
  public static synchronized ConnectionPool getInstance() {
  if (instance==null)
   instance=new ConnectionPool ();
return instance;
  }
  private ConnectionPool () {
  ……
  }
  }
  
到这里,要产生数据库连接的任务已经完成了。
5.利用Template Method模式来提取操作框架
对数据库的操作可以分为两类:对于第一类操作,会产生一定的结果集,如查询数据库;另一类操作,则只是对原有的数据库的变更,不会产生结果集,比如插入操作、更新操作。对于这两种情况,我们可以分别封装成相应的类。但我们发现,这两个类在操作时有很多的相同点。基本流程都是先获取数据库连接,然后生成Statement对象,再在这个Statement对象上调用方法执行SQL语句,这些步骤可以提取成一个方法execute()到一个父类里面,可称为DbBean类。这个父类只用公布出一个方法让子类去重载,这种方法往往被称为勾子方法,在这里不妨称为executeSql()。有了这个父类,对于两种不同的操作类型,会产生两个子类,不妨称为SelectBean与UpdateBean。对于不同的子类,只是重载父类中的勾子方法executeSql(),执行不同的数据库访问,不用去关心准备这个访问所要做的事。
6.引入Adapter模式来解决已有接口的不一致
在JDBC提供的接口里面,对数据库访问的方法分别为executeQuery()与executeUpdate(),在以上引入Template Method模式后,得在子类中去重载父类中公布出来的勾子方法executeSql(),这个勾子方法的名字是惟一的,这样,为了让我们的特定数据库访问能很好地衔接上去,我们可以引入Adapter模式,把这两个不同的方法适配成executeSql()。注意,因为executeQuery()方法有一个返回值,我们有必要在包含它的子类里面加上一个ResultSet类的成员变量rs。这样,在executeSql()方法里面,只要把executeQuery()的返回值赋给rs就可以了。图1是引入以上两个模式后形成的框架图。
7.引入Facade模式使操作接口更接近业务逻辑
在对数据库查询时,使用JDBC已经提供的接口executeQuery()时,返回给我们的是一个ResultSet对象,里面依次存放着要查询的每一列。程序员如果要获取所需的信息,往往得通过调用返回对象的getObject(int i)方法。这样做,一方面,很不直观,另一方面,代码的耦合性很高。对此,我们想到了引入Adaptor模式,这样可使我们的接口更进一步脱离数据库操作,从而可更关注业务逻辑。
假设现在有一个学生信息表T_Student,里面的信息为ID,Name,Age,其基本表结构如下:
对于这个表的查询,我们的目的就是能用getId(),getName(),getAge()这样的方法来获取数据。基于这样的目的,现在要做的就是把查询所得到的数据如何正确地定位到我们方法的返回值。对于数据库查询,我们发现,在查询语句中要查询的记录的序号与返回结果中的序号是一一对应的,利用这一点,可以把要查询的字段名放在一个Vector里面,如上面Vector中的内容可以是(“Id”,“Name”,“Age”),我们要执行的SQL语句很容易通过这些字段名来拼接,其执行结果是按给出的顺序放在ResultSet对象里面的。最后,对于特定的函数调用,如getId(),可以通过Java提供的Reflection机制获取函数名,然后去掉前面的get字符,再在字段名Vector里用indexOf(Object o)方法获取字段名所对应的序号index,这也是其查询结果ResultSet里的序号,通过它可以从查询结果ResultSet里面通过getObject(index)得到我们要的结果。我们可以把这些不变的代码提取到父类SelectBean中,这样做的好处是以后对于不同的表结构可以生成相应的子类。我们只用定义一个Vector变量,放上我们要查询的字段名字符串,并定义相应的get函数。当我们调用它们时,只需调用以上父类的公共匹配代码,即可获得正确的数据。以下是针对以上表结构引入Facade模式后的效果图与代码片断:
……
String name,id,age;
StudentSelect student = new StudentSelect();
student.execute();
name =student.getName();
id =student.getId();
age= student.getAge()
……
对于对数据库更新的SQL语句,也可利用以上的机制,做法是类似的,在此不再赘述。
本文提供了在Java数据库编程中引入设计模式的一个思路。在实际中,我们基于以上的设计思路实现了一个框架,基于这个框架,编写Java数据软件的效率大大提高。当然,本文提供了一个整体的设计思路,在实际中,可以根据特定的情况,修改其中的一些模块,比如,数据库的连接可以从J2EE中的数据源获取。对此,读者可以自行取舍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: