作者:sure160
email: [email protected]
日期:6/13/2001 12:46:36 PM
简介:本文探讨了关系数据库中的实体对象在面向对象语言中如何抽象、实现,并提出一种实现方案。
一、为什么要使用实体对象的概念
实体对象指的是可永久存储的数据对象,通常可以用关系数据库的一张数据表或一张主表和与之连接的几张子表来表示。为什么要引入实体对象的概念呢?我可以肯定您是看过关于面向对象优点的长篇大论的,不过我觉得有必要再唠叨两句,因为不是所有用C++或JAVA编程的人都是使用面向对象的方式想问题的。
在现实世界中,对象比它的属性要稳定,所以数据要抽象成对象。比如由于需求的修改,一个图书管理系统要显示更多的书目详细信息,图书的属性发生了变化,而图书这个对象并没有变,和其他对象(例如书架、借阅者)之间的关系也没有变。用一个数据对象来保存书目信息的程序修改起来要简单的多。
把实体对象如何永久储存的方法封装到对象中可以实现使用对象的外部程序的与数据库无关,便于程序的移植。
在程序设计中使用实体对象概念把面向对象分析、面向对象设计、面向对象编码着几个步骤连贯和一致。
可以减少外部程序中复杂性,使用这些实体对象的程序只需要简单的调用insert()或update()的方法,而不用去写讨厌的SQL语句。
但是,由于历史原因,即使象Java这样的新兴语言,也没有在所有地方完全利用面向对象的思想。让我们看看JDBC吧,这是一个号称用对象封装的数据库接口。可是它封装的是什么呢?连接、语句、结果集和存储过程。这其实并不是我们设计系统所关心的东西,我们关心的是数据对象本身,而不是它从数据库中提取的方法。当然,JDBC本身也不该受到太多的指责,因为他本来的目标就是封装、屏蔽关系型数据库之间的差异,而不是企图实现一个面向对象的数据库。
EJB第一次引起我的注意就是因为它提出的Entity Bean,也就是实体对象。它对实体对象提供了一套完整的实现思路,但是我认为它太复杂了,主要原因是EJB想要做的事太多了。大部分情况下我并不需要分布式处理,我也不需要把实体对象存储到文件中去。我需要的仅仅是在一个本地运行的基于数据库的程序。
二、EJB如何实现的实体对象
刚才提到了EJB已经实现了实体对象,那么让我们看看它是如何实现的。EJB中Entity Bean的对象实际上是对数据对象的一种完美的抽象,在这里我们几乎看不到数据库管理系统的作用。一个实体对象有几种状态,在内存中、在磁盘缓存中、或者在数据库中,实体对象的这些状态通常我们是不关心的,EJB的容器在必要的情况下会自动转换对象的状态,也就是说自动把它存到数据库中,或从数据库中取出。我们要访问一个数据对象,要向一个对象容器提出申请,由它返回一个对象实例供我们使用。一个Entity Bean对应于数据表中的一行。如果我们访问的是同一行数据,对象容器返回的是不同的对象,但都指向同一个Entity Bean,并把我们所有的方法请求都发送给这个Entity Bean。实际上EntityBean的容器基本实现了一个面向对象的数据库。它这种实现方法带来几个显著的问题:
运行效率非常低。JAVA的速度慢是个老问题了,EJB的速度慢不光是因为大量代码用JAVA实现,而且由于它的结构,要根据数据表中的某一个属性查出一行数据,必须首先用SQL查询查找到这一行的主键(Primary Key),然后通过主键来找到这个Bean,如果这个Bean不在内存中--很不幸,这种情况经常发生,那么实际上是执行了两次SQL查询才找到一行数据。
容器本身要管理事务,以防数据的污读、污写、死锁等等一系列问题。本来DBMS管理这类问题已经有很多年经验了,已经相当完美的解决了这些问题,可是EJB不得不通过一个Transcation Server来管理这些问题。这使得容器的代码变得极其复杂,另外编程人员也不得不重新熟悉这些接口。
由于bean 中的数据是否存储在数据库里是由容器管理的,那么其他程序访问数据库会带来数据同步的问题。因此,在EJB架构中,外部程序不能直接访问数据库,只能通过EJB访问。
三、我们实现的目标
我们只想把数据库对象更好的封装起来,为什么要购买别人昂贵的代码?为什么要为我们不会用到的分布式去牺牲大量的性能。我们想要尽量使用DBMS的功能,以实现最佳的性能和最简化的代码。
事务处理最好还是用DBMS来管理,因为它一向管得很好,而且事务处理的代码很复杂,我不打算自己来完成。
我不打算用同一个对象来指向数据库的一行。数据库的一行数据在程序中可能有多个对象,这些对象都应该是临时对象,而不是永久对象。他们的共享问题由DBMS本身加锁来解决。
由于我们只是为访问DBMS提供了一个接口,外部程序完全可以不通过这个接口来访问数据库。
实现后,使用实体对象的代码要简单。例如,数据库里有一个表account,它只有两个字段accountid和name,我们把它作为一个实体对象Account,假设我们要完成从数据库查询、修改、插入,使用它的代码片段如下:
Connection conn=ConnectionPool.getConn(); //也可以通过标准的DriverManager得到数据库连接,这是完全一样的
Conn.setAutoCommit(false); //如果不使用事务,这一行可以省去
Account a1=new Account(conn);
a1.getByAccountId(1); //查找到相应记录
System.out.println(a1.name);
a1.getByAccountIdForUpdate(1); //如果企图修改一个对象,必须通过forUpdate系列的方法得到这个对象
a1.name="new name";
a1.update(); //修改原有记录
Account a2=new Account(conn);
a2.accountId=3;
a2.name="姚大";
a2.insert(); //插入一条新记录
conn.commit();
实体对象的属性通过方法修改是比较理想的方式,如用getName(),setName()两个方法访问Name属性。这还可以解决属性之间相互关联的问题。例如,表中有一个地区代码和地区名称两个域,必须保持一致,这就可以考虑在属性设置方法中实现。在这里我们为了简单,直接通过属性修改,在一般情况下,我觉得也是可以接受到。
有一点必须注意的就是多线程程序所带来的数据完整性问题。对于我们常使用的从数据库读取数据到对象中->修改对象属性->更新到数据库这个流程,非常容易出现数据完整性破坏问题。比如一个进程中甲对象读取数据后,另一个进程中乙对象又修改了同一数据,这时甲对象再次更新数据库会带来污写。解决的办法是对象增加一个方法给数据库的这条记录加锁。例如Account.getByAccountId函数改为Account.getByAccountIdForUpdate,这个函数中相应的sql语句(ORACLE数据库)改为"select AccountId,name from account where accountId=? for update",这样数据取出后就自动加锁,这个锁将会在事务提交或回滚时释放。for update在SQLServer相应的语法为holdlock。
说到数据库加锁的问题就不能不考虑到数据库死锁的可能。想完全避免死锁是很困难的,只有尽量降低这种可能性。方法是:1、尽量少使用forUpdate这种函数,只有在更改数据库数据时才使用。查询的时候不要用,如果查询后根据某个条件有可能修改,那么在查询时不加锁,在修改前重新调用forUpdate函数加锁。2、尽量以某个特定的顺序加锁。例如有表A和表B,两个程序都要同时更新这两个表,最好都是先访问表A,再访问表B。
Oracle有个很好的功能就是自动检测死锁。如果发生死锁,会回滚一个事务,并返回一个SQL错误,我们的程序要检测这个异常,处理程序中可能的错误。
上面说到的对象中,只有getByXXX()这样的方法,这种方法只会返回唯一的对象,如果想要返回一组对象,这时需要一个辅助类来实现。这个辅助类称为对象浏览器EntityBrowser。再实体对象中返回一个对象浏览器的方法一般命名为getAllByXXX()
使用对象浏览器EntityBrowser要列出所有account表中的id和name的代码如下,其实这个对象浏览器和Java定义的Enumeration接口的最大区别就是它有一个close方法。请看下面的代码片断,它输出所有的Accout对象。
Connection conn=ConnectionPool.getConn();
Account a1=new Account(conn);
EntityBrowser browser=a1.getAll();
System.out.println("==Account List==");
While (browser.hasMoreElement()) {
Account a=(Account)browser.nextElement();
System.out.print(a.accountId);
System.out.print("--");
System.out.println(a.name);
}
browser.close();
以上就是我们要实现的实体对象,下面介绍如何编写一个实体对象。
四、实现的代码解释
首先,下面的代码定义一个所有实体对象的基础类EntityObject,这是一个抽象类,不能直接使用,但为其它实体对象定出了一个结构。
Import java.sql.*;
/**所有实体对象基础类*/
abstract public class EntityObject {
protected java.sql.Connection _conn;
private boolean _dbStored;
/**实体对象需要用一个数据库连接初始化,这样可以利用这个连接做事务提交或回滚*/
public EntityObject(Connection conn) {_conn=conn;_dbStored=false;}
/**这个方法用来插入新记录,子类必须重定义这个方法*/
public void insert() throws SQLException{ _dbStored=true;}
/**这个方法用来修改数据库原有记录,子类必须重定义这个方法*/
public void update() throws SQLException {_dbStored=true; }
/**这个方法用来删除数据库原有记录,子类必须重定义这个方法*/
public void delete() throws SQLException {_dbStored=false; }
/**这个方法用来把数据库select语句得出的结果映射到对象的属性中去,子类必须重定义这个方法*/
public void _setAttribute(ResultSet rs) throws SQLException {_dbStored=true; }
/**这个方法可以判断
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
自己写的一个lucene知识点集合 (554个子文件)
_k.cfs 4.69MB
test_01.class 8KB
IndexHTMLTidy.class 6KB
test_03_Query.class 5KB
IndexFiels.class 3KB
File2DocumentUtils.class 3KB
IndexHTML.class 2KB
test_02_Analyzer.class 2KB
Seanch.class 2KB
Test1.class 2KB
QueryResult.class 1KB
IndexHTMLTidy$ReaderToInputStream.class 703B
.classpath 694B
segments.gen 20B
lucene-core-2.9.1.jar 1.05MB
je-analysis-1.4.0.jar 878KB
Tidy.jar 174KB
lucene-analyzers-2.2.0.jar 71KB
lucene-demos-2.9.1.jar 55KB
lucene-highlighter-2.2.0.jar 28KB
test_01.java 7KB
IndexHTMLTidy.java 5KB
test_03_Query.java 4KB
IndexFiels.java 2KB
Test1.java 2KB
File2DocumentUtils.java 2KB
test_02_Analyzer.java 1KB
IndexHTML.java 1KB
Seanch.java 1024B
QueryResult.java 682B
.project 387B
segments_1a 274B
实体对象的抽象以及一种基于数据库的实现(转).txt 16KB
转:第一部分:EJB 体系结构的历史和目标.txt 16KB
XP 精华----如何使 Java 项目获得更大成功.txt 16KB
简单的例子.txt 16KB
转载--微软98年关于MTS和EJB的比较说明文件.其实Sun也有类似的对比文件,我忘记在那里了!(1).txt 16KB
第二部分:EJB 编程模型(转).txt 15KB
Declarations and Access Control (2).txt 15KB
用 JSP 在客户端生成 JavaScript 代码来实现表单校验.txt 15KB
Overloading overriding runtime type and object orientation (2).txt 15KB
SSL與數位認證.txt 15KB
Java2的安全新特性下的Applet数字签名具体实现方法.txt 14KB
soap规范(1).txt 14KB
ejb一则,[email protected]多多交流哦.txt 14KB
Java 编程技术中汉字问题的分析及解决(转).txt 14KB
JDBC技术介绍 转.txt 14KB
Java 程序编码规范.txt 14KB
将 Microsoft 的 Internet Information Server 用作 Java servlet 引擎(转).txt 14KB
Threads.txt 14KB
servlet2.3.txt 14KB
一个连接池的例子(来自JIVE)(1).txt 13KB
转载--微软98年关于MTS和EJB的比较说明文件.其实Sun也有类似的对比文件,我忘记在那里了!(2).txt 13KB
soap规范(2).txt 13KB
JavaServer PagesTM 白皮书.txt 13KB
5.3 CORBA技术及实例.txt 13KB
Beginner Using Servlets to display, insert and update records in database.(3).txt 13KB
WebSphere快速入门(2).txt 13KB
在JSP页面中实现检索数据的分页显示.txt 13KB
Java 编程技术中汉字问题的分析及解决(转自IBM).txt 13KB
JDBCTM 指南:入门.txt 13KB
WebSphere快速入门(22).txt 12KB
JSP高级技术如何开发动态网站.txt 12KB
Javajsp 好的入门文章共赏.txt 12KB
JavaServer Pages (JSP) 1.0简单介绍 ---III.txt 12KB
JDBC 入门.txt 12KB
Beginner Using Servlets to display, insert and update records in database.(1).txt 12KB
三种Web开发主流技术ASP-PHP-JSP的评价[转载] --希望给大家作为参考.txt 12KB
值得关注:Java 1.4 即将发布版本的性能和新功能一览(转自IBM developerWorks).txt 12KB
WebSphere快速入门(14).txt 12KB
Overloading overriding runtime type and object orientation (1).txt 11KB
用连接池提高Servlet访问数据库的效率 (-).txt 11KB
Java Web Start 1.0 developer's guide (2).txt 11KB
Java 线 程 的 讨 论 与 应 用 (转).txt 11KB
Beginner Using Servlets to display, insert and update records in database.(2).txt 11KB
JSPServlet 中的汉字编码问题(转).txt 11KB
LICENSE.txt 11KB
用Java绘制K线 (转2).txt 11KB
JSP - FAQ (2).txt 11KB
Java性能的优化(下)(转).txt 11KB
用 Java 保存位图文件(转).txt 11KB
在网页上发布统计曲线.txt 11KB
最大限制地提高代码的可重用性(转).txt 11KB
第三部分:布署和使用 Enterprise JavaBeans 组件(一)(转).txt 11KB
(3).txt 11KB
Good Java Style Part 2.txt 11KB
WebSphere快速入门(17).txt 11KB
soap规范(完).txt 10KB
Operators and Assignments(1).txt 10KB
用JSP和数据库做的购物车的源程序:(欢迎大家指点!).txt 10KB
EJB概述(下).txt 10KB
将 Microsoft 的 Internet Information Server 用作 Java servlet 引擎 一 (给学过ASP的朋友).txt 10KB
如何用 servlet 打开非 HTML 格式的文档(转).txt 10KB
困扰JSP的一些问题.txt 10KB
Java的网络功能与编程 一(转)---建议放入精华区.txt 10KB
sad.txt 10KB
一些非常有用的JAVA常用方法( 2).txt 10KB
ftp站点荟萃,你自己找找看看。不好意思!.txt 10KB
用JAVA转换简繁体的基础知识 (不用对照表,用算法实现).txt 10KB
Java混淆编译器(转apusic.com).txt 10KB
共 554 条
- 1
- 2
- 3
- 4
- 5
- 6
资源评论
wocaoni2009
- 粉丝: 2
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功