dao技术
dao技术
使用JBoss和PostgreSQL-----快速开发EJB和J2EE Web Application
hanqw3 原创 (参与分:20,专家分:30) 发表:2003-8-4 上午11:46 更新:2003-8-4 下午2:49 版本:2.0 阅读:4218次
使用JBoss和PostgreSQL-----快速开发EJB和J2EE Web Application
Developing J2EE Web Application on Jboss and PostgreSQL(chinese version)
作者:Han QW, 转载请指明出处 如有不当之处,敬请指出
先安装JSDK,再安装JBoss.
安装JSDK,必须获得一套对应于用户的操作系统的JDK,
我的安装的文件目录是
WINDOWS2000: d:\s1studio_jdk\j2sdk1.4.1
linux: /root/s1studio_jdk/j2sdk1.4.1
为了用EJB, 需要一个j2ee-1.3.jar或者j2ee-1.2.jar,
如果安装了Sun One Studio 或者 J2EE (www.sun.com )这个文件已经有.
把这个文件放在classpath路径上.
或者使用jboss-j2ee.jar, 安装JBoss后在$JBoss\client中可找到.
建议安装Sun One Studio, 用Sun One Studio编译JAVA源程序,
不用设置classpath, 省去不少过程.
安装JBoss:
把JBoss的压缩包解开,放在任一目录上,
我的安装的文件目录是
/dose/jboss-3.0.4_tomcat-4.1.12 (REDHAT8.0)
E:\jboss-3.0.4_tomcat-4.1.12 (WINDOWS2000)
WINDOWS2000, linux共用同一套JBoss.
配置JBoss:
启动JBoss需要执行一个脚本文件:
linux:run.sh
WINDOWS对应的是:run.bat
(1)
在JBoss\bin\run.bat (for Windows)开头插入一行
set JAVA_HOME = d:\s1studio_jdk\j2sdk1.4.1
在JBoss\bin\run.sh (for Linux)开头插入一行
JAVA_HOME="/root/s1studio_jdk/j2sdk1.4.1"
或者
(2)设置系统环境变量JAVA_HOME,指向JDK
运行JBoss, run.sh或者run.bat
当看到启动JBoss的信息时,说明启动了.
服务器简单的测试:
JBoss默认的WEB端口为8080,我们可以在打开一个浏览器输入地址
http://localhost:8080/jmx-console
当在浏览器看到JBoss的信息时,说明安装配置JBoss成功了.
建立下面的目录和文件(注意大小写).
FIRST.EAR
|
|-----META-INF (application.xml)
|
|-----First.jar
| |-----META-INF (ejb-jar.xml,jboss.xml)
| `-----Dev
| |-----First(FirstSession.java, FirstSessionHome.java, FirstSessionBean.java)
| |-----Delegate(NewDelegate.java)
| `-----Dao(MysqlDao.java)
|
`-----First.war(index.jsp)
|
`-----WEB-INF (jboss-web.xml, web.xml)
|-----classes
`-----lib
/*
**
**MysqlDao.java
**
*/
package Dev.Dao;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MysqlDao {
public Connection getConnection() throws Exception {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/PostgresDS");
Connection conn = null;
Statement stmt = null;
try {
conn = ds.getConnection();
} catch (SQLException sqlEx) {
System.out.println("Error connect to pool.");
}
return conn;
}
public String getName(String id) throws Exception {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String name = "";
try {
conn = getConnection();
if ( conn !=null )System.out.println("Get conecttion. "+ conn.toString());
stmt = conn.createStatement();
if ( stmt !=null )System.out.println("Get Statement. "+ stmt.toString());
String sql = "SELECT * from users where id = '"+id+"'";
System.out.println("Sql from getId(): "+sql);
rs = stmt.executeQuery(sql);
if ( rs !=null )System.out.println("Get result. ");
if (rs.next()){
name = rs.getString("name");
}
} catch (Exception sqlEx) {
System.out.println("Error from getName().");
System.out.println("Error from DAO.getName() :" + sqlEx.getMessage());
}finally {
if (conn != null) {
try { conn.close(); } catch (Exception sqlEx) { }
}
}
return name;
}
public String getCountry(String id) throws Exception {
Connection conn = null;
Statement stmt = null;
String name = "";
try {
conn = getConnection();
stmt = conn.createStatement();
String sql = "SELECT * from users where id = '"+id+"'";
System.out.println("Sql from getCountry(): "+sql);
java.sql.ResultSet rs = stmt.executeQuery(sql);
if (rs.next())
{
name = rs.getString("Country");
}
} catch (SQLException sqlEx) {
System.out.println("Error from getCountry().");
}finally {
if (conn != null) {
try { conn.close(); } catch (Exception sqlEx) { }
}
}
return name;
}
}
/*
**
**NewDelegate.java
**
*/
package Dev.Delegate;
import java.lang.*;
import Dev.First.*;
public class NewDelegate {
Dev.First.FirstSession bean = null;
public NewDelegate( ){
try {
javax.naming.InitialContext ctx = new javax.naming.InitialContext();
Object objref = ctx.lookup("ejb/FirstSession");
Dev.First.FirstSessionHome testBean = (Dev.First.FirstSessionHome)
javax.rmi.PortableRemoteObject.narrow
(objref,Dev.First.FirstSessionHome.class);
bean = testBean.create();
System.out.println("From JSP");
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
}
public String Welcome() {
String msg = "";
try {
msg = bean.Welcome();
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
return msg;
}
public String getName(String id) {
String name = "";
try {
name = bean.getName(id);
} catch (Exception NamingException) { NamingException.printStackTrace();}
return name;
}
public String getCountry(String id) {
String country = "";
try {
country = bean.getCountry(id);
} catch (Exception NamingException) { NamingException.printStackTrace();}
return country;
}
}
/*
**
**FirstSession.java
**
*/
package Dev.First;
import java.lang.*;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public interface FirstSession extends javax.ejb.EJBObject{
public String Welcome() throws java.rmi.RemoteException;
public String getName(String id) throws java.rmi.RemoteException;
public String getCountry(String id) throws java.rmi.RemoteException;
}
/*
**
**FirstSessionHome.java
**
*/
package Dev.First;
import java.lang.*;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public interface FirstSessionHome extends javax.ejb.EJBHome{
public FirstSession create() throws javax.ejb.CreateException, java.rmi.RemoteException;
}
/*
**
**FirstSessionBean.java
**
*/
package Dev.First;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class FirstSessionBean implements SessionBean{
public void ejbCreate() throws CreateException {
}
public String Welcome(){
String msg="Hello! This My Session Bean From Jboss.";
System.out.println(msg);
return msg;
}
public String getName(String id){
String name = "";
System.out.println("From bean before getName :"+ name);
try{
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
name = dao.getName(id);
System.out.println("From bean after getName :"+ name);
}catch(Exception e){ System.out.println(e.getMessage());}
return name;
}
public String getCountry(String id){
String country = "";
try{
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
country = dao.getCountry(id);
}catch(Exception e){ }
return country;
}
public void setSessionContext( SessionContext aContext ) throws EJBException {
}
public void ejbActivate() throws EJBException {
}
public void ejbPassivate() throws EJBException {
}
public void ejbRemove() throws EJBException {
}
}
/*Don't put the following lines into index.jsp
**
**index.jsp
**
*/Don't put the above lines into index.jsp
<%@page language="java" %>
<%
String msg = "";
String msg1 = "";
Dev.Delegate.NewDelegate nn = new Dev.Delegate.NewDelegate();
if (request.getParameter("id") != null &&
request.getParameter("id") != ""&&
!request.getParameter("id").equals("")){
String id = request.getParameter("id");
String name = "";
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
name = nn.getName(id); //access database through session bean
//name = dao.getName(id); //access database directly
if(name!= null && !name.equals("")){
msg1 ="Welcome " + name +" ! You are from "+ dao.getCountry(id)+ " .";
}else{
msg1 ="Please Check Your ID. : " + id;
}
}
msg = nn.Welcome() ;
%>
Welcome
<%= msg %>
<%=(msg1 == "")? "":msg1 + "
Connect to Database OK." %>
不要将此以上5行存入文件, 下同.
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
First
First
My First Session Bean
FirstSession
Dev.First.FirstSessionHome
Dev.First.FirstSession
Dev.First.FirstSessionBean
Stateless
Container
FirstSession
ejb/FirstSession
"http://www.jboss.org/j2ee/dtd/jboss-web.dtd">
jdbc/PostgresDS
javax.sql.DataSource
java:/PostgresDS
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
Postgresql driver
jdbc/PostgresDS
javax.sql.DataSource
Container
First
First.war
/First
First.jar
编译JAVA源程序,生成class文件.
进入JAVA源程序目录, 运行:
javac -classpath %classpath%;%jboss%\server\default\deploy\First.ear\First.jar *.java
或者
javac -classpath %jboss%\server\default\deploy\First.ear\First.jar;%jboss%\client\jboss-j2ee.jar *.java
Copy 目录First.ear to jboss\server\default\deploy.
打开浏览器输入地址 http://localhost:8080/First
到此, 在浏览器看到: Hello! This My Session Bean From Jboss.
说明这个EJB工作了.
如果按按钮, 没反应或出错. 原因没安装配置数据库, 下面安装配置Postgres数据库
For Windows2000
下载 PgSQL731wina1.exe (http://www.postgresql.org),
Finally you will see the next line, you need enter the password for Administrator
最后你将看下一个行,你必须为用户Administrator输入password.
********************
Enter password of user `.\Administrator':123456
********************
记下此password, 我的口令是123456.
从开始菜单 > Programm > PostgresSQL > Adjust PostgresSQL Configuration file
它将在Wordpad中打开PostgresSQL Configuration文件, 找到下列行,
#
# Connection Parameters
#
#tcpip_socket = false
#ssl = false
#max_connections = 32
#superuser_reserved_connections = 2
#port = 5432
修改编辑:
#
# Connection Parameters
#
tcpip_socket = true
#ssl = false
#max_connections = 32
#superuser_reserved_connections = 2
port = 5432
接着,保存文件.
起动PostgresSQL服务器:
开始菜单>Programm>PostgresSQL>Utilies>Start PostgresSQL server
起动命令行:
开始菜单>Programm>PostgresSQL>Utilies>Command Shell
执行下列命令,准备数据,
Administrator@SAN /
$ dir
$ cd bin
$ createdb test
$ psql test
test=# create table users
test-# (name varchar(20),
test(# id varchar(20),
test(# country varchar(20));
test=# insert into users values ('Sam', '123', 'China');
test=# insert into users values ('Tom', '321', 'USA');
test=# insert into users values ('Sean', '231', 'France');
test=# select * from users;
name | id | country
------+-----+---------
Sam | 123 | China
Tom | 321 | USA
Sean | 231 | France
(3 rows)
test=#
到此, 数据准备就绪.
For RedHat:
以root登陆, 执行下列命令,准备数据,
mkdir /usr/local/pgsql/data
chown postgres /usr/local/pgsql/data
su - postgres
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
Open and edit /usr/local/pgsql/data/pg_hba.conf
local all trust
host all 127.0.0.1 255.255.255.255 trust
just delete #, and save.
[root@localhost root]# su - postgres
-bash-2.05b$ /usr/bin/postmaster -i -D /usr/local/pgsql/data >logfile 2>&1 &
-bash-2.05b$ /usr/bin/createdb test
-bash-2.05b$ /usr/local/pgsql/bin/psql test
test=# .......the following same as Windows2000
到此, 数据准备就绪.
执行shutdown.bat or shutdown.sh, 停止Jboss Server.
找到JDBC drive.
为了在Jboss中使用连接池,需要拷贝jdbc drive 到Jboss/server/default/deploy , 在linux 我们能找到/usr/share/pgsql/pgjdbc2.jar,在wondows2000,我们能找到PostgreSQL\usr\share\postgresql\java\postgresql.jar
把其中之一复制到Jboss/server/default/deploy
配置Jboss
(1) 复制 $Jboss/examples/jca/postgres-service.xml 到 $Jboss/server/default/deploy/
(2) 打开编辑Jboss/server/default/deploy/postgres-service.xml
PostgresDS
jdbc:postgresql://localhost/test
org.postgresql.Driver
Administrator
123456
In my example, set Username Administrator, password 123456 for windows 2000
set Username Postgres, no password for Linux.
在我的例子中,
windows2000, 用户:Administrator,password:123456
Linux(RH8.0), 用户:Postgres, 没有password
因为PostgresSQL和windows2000使用不同的default用户名,所以在linux和window2000中这文件不同.当然,你可以加相同的PostgresSQL用户名和password在linux和window2000中, 这样这文件就相同了.
保存文件.
(3) 打开编辑 $Jboss/server/default/conf/standardjbosscmp-jdbc.xml
找到:
java:/DefaultDS
Hypersonic SQL
加入:
java:/PostgresDS
Postgres
保存文件.
(4) open and edit $Jboss/server/default/conf/standardjaws.xml
找到:
java:/DefaultDS
Hypersonic SQL
false
加入:
java:/PostgresDS
Postgres
false
------
回复此文章 | edit | hide
回复主题:Re:dao技术 | 作者: haohao | 军衔:六级军士 | 发表时间:2004-07-27 10:20:33
=============Student.java==========
import java.sql.*;
public class Student implements java.io.Serializable{
private String id;
private String name;
private Date birthday;
public Student(){}
public Student(String id, String name, Date birthday){
this.id = id;
this.name = name;
this.birthday = birthday;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
}
=================Course.java======================
public class Course implements java.io.Serializable{
private String id;
private String name;
private String description;
public Course() {}
public Course(String id, String name, String description){
this.id = id;
this.name = name;
this.description = description;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name ) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}
==============SMdao.java==================
import java.sql.*;
public interface SMdao {
public Student createStudent(String id, String name, Date birthday);
publc Course createCourse(String id, String name, String description);
public Student findStudent(String id);
public Course findCourse(String id);
public void clean();
}
==============FileSMdaoImpl.java==============
import java.util.Properties;
import java.sql.*;
import java.io.*;
public class FileSMdaoImpl implements SMdao {
private Properties pro;
private final static String SFILE_URL = "student.file.url";
private final static String CFILE_URL = "course.file.url";
public FileSMdaoImpl(Properties pro){
this.pro = pro;
}
public Student createStudent(String id, String name, Date birthday) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Student stu = null;
try {
fos = new FileOutputStream(pro.getProperty(FILE_URL), true);
oos = new ObjectOutputStream(fos);
stu = new Student(id, name, birthday);
oos.writeObject(stu);
} catch(Exception e) { stu = null; }
finally{
try { if(oos != null) oos.close(); } catch(Exception e){}
try { if(fos != null) oos.close(); } catch(Exception e) {}
}
return stu;
}
public Course createCourse(String id, String name, String description){
return null;
}
public Student findStudent(String id) {
return null;
}
public Course findCourse(String id) {
return null;
}
public void clean() {}
}
==============DBSMdaoImpl.java==============
import java.sql.*;
import java.util.Properties;
public class DBSMdaoImpl implements SMDao {
private Connection con;
private final static String DBDRV = "db.driver";
private final static String DBURL = "db.url";
private final static String DBUSER = "db.user";
private final static String DBPASSWD = "db.password";
public DBSMdaoImpl(Properties pro) {
try {
Class.forName(pro.getProperty(DBDRV));
String user = pro.getProperty(DBUSER);
String passwd = pro.getProperty(DBPASSWD);
if(user != null)
con = DriverManager.getConnection(pro.getProperty(DBURL),
user, passwd);
else
con = DriverManager.getConnection(pro.getProperty(DBURL));
} catch(Exception e){}
}
public Student createStudent(String id, String name, Date birtyday) {
if(con == null) return null;
Student stu = null;
PreparedStatement stm = null;
try {
stm = con.prepareStatement("insert into student(id, name, birthday) " +
"values(?, ?, ?)");
stm.setString(1, id);
stm.setString(2, name);
stm.setDate(3, birthday);
if(stm.executeUpdate() > 0)
stu = new Student(id, name, birthday);
}catch(Exception e){}
finally{
try {if(stm != null) stm.close();}
catch(Exception e) {}
}
return stu;
}
public Course createCourse(String id, String name, String desc) { return null; }
public Student findStudent(String id) { return null; }
public Course findCourse(String id) { return null; }
public void clean() {
try {
if(con != null) con.close();
}catch(Exception e) {}
}
}
===============SMdaoFactory.java===============
import java.util.*;
public class SMdaoFactory {
Properties pro;
public static final String TYPE_FILE = "file";
public static final String TYPE_DB = "database";
private String type;
private static SMdaoFactory factory;
static{ factory = new SMdaoFactory();}
private SMdaoFactory() {
}
public static SMdaoFactory newInstance() { return factory; }
public void setType(String type) { this.type = type; }
public void setProperties(Properties pro) { this.pro = pro; }
public SMdao createSMdao() {
if(type.equals(TYPE_FILE))
return new FileSMdaoImpl(pro);
else
return new DBSMdaoImpl(pro);
}
}
=================Main.java=========================================
import java.io.*;
import java.util.*;
import java.sql.*;
public class Main{
public static void main(String args[]){
Properties pro = new Properites();
try {
pro.load(Main.class.getResourceAsStream("conf.properties");
}catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
SMdaoFactory factory = SMdaoFactory.newInstance();
factory.setType(SMdaoFactory.TYPE_DB);
factory.setProperties(pro);
SMdao dao = factory.createSMdao();
GregorainCalendar calendar = new GregorainCalendar();
calendar.set(Calendar.YEAR, 1975);
calendar.set(Calendar.MONTH, 2);
calendar.set(Calendar.DAY_OF_MONTH, 21);
java.sql.Date birthday = new java.sql.Date(calendar.getTimeInMills());
Student stu = dao.createStudent("12345", "George", birthday);
}
}
==============conf.properties===================
db.driver=COM.pointbase.jdbc.jdbcUniversalDriver
db.url=jdbc:pointbase:server://george/sample
db.user=pbpulic
db.password=pbpublic
student.file.url=student
course.file.url=course
------
回复此文章 | edit | hide
回复主题:Re:Re:dao技术 | 作者: haohao | 军衔:六级军士 | 发表时间:2004-07-27 10:23:32
http://www.matrix.org.cn/article/853.html
免费注册
用户登陆
帮助中心
JAVA首页 Matrix动态 Java专栏 Java下载 Java网站 用户中心 开源项目 JAVA论坛
您现在位于: 首页 → Java专栏---浏览技术文章
读《J2EE核心模式》(DAO模式)
2004年4月7日 作者:martin Matrix-与Java共舞
读《J2EE核心模式》(DAO模式)
from Martin的blog: http://www.matrix.org.cn/blog/martin/
很多的J2EE应用程序需要使用持久性数据(数据库、文件等)。不同的程序,持久性存储是各不相同的,并且用来访问这些不同的持久性存储机制的API也有很大的不同。如果应用程序要在不同的持久性存储间迁移,这些访问特定持久存储层的代码将面临重写。
如何解决这个问题?且看"DAO模式"
数据访问对象(Data Acess Object) 模式
一.环境
根据数据源不同,数据访问也不同。根据存储的类型(关系数据库、面向对象数据库、文件等等)和供应商实现不同,持久性存储(比如数据库)的访问差别也很大。
二.问题
许多真是的J2EE应用程序需要在一定程度上使用持久性数据。对于许多应用程序,持久性存储是使用不同的机制实现的,并且用来访问这些不同的持久性存储机制的API也有很大的不同。
比如,应用程序使用实体bean(这里应该是指BMP的bean,CMP的bean已大大降低了与RDBMS的耦合)的分布式组件来表示持久性数据,或者使用JDBC API来访问驻留在某关系数据库管理系统(RDBMS)中的数据,这些组件中包含连接性性和数据访问代码会引入这些组件与数据源实现之间的紧密耦合。组件中这类代码依赖性使应用程序从某种数据源迁移到其他种类的数据源将变得非常麻烦和困难。当数据源变化时,组件也需要改变,以便于能够处理新类型的数据源。
(举个例子来说,我们UPTEL系统是使用JDBC API对 ORACLE数据库进行连接和数据访问的,这些JDBC API与SQL语句散布在系统中,当我们需要将UPTEL迁移到其他RDBMS时,比如曾经迁移到INFORMIX,就面临重写数据库连接和访问数据的模块。)
三.作用力
1.诸如bean管理的实体bean、会话bean、servlet等组件往往需要从持久性存储数据源中检索数据,以及进行数据存储等操作。
2.根据产品供应商的不同,持久性存储API差别也很大,这些API和其能力同样根据存储的类型不同也有差别,这样存在以下缺点,即访问这些独立系统的API很不统一。
3.组件需要透明于实际的持久性存储或者数据源实现,以便于提供到不同供应商产品、不同存储类型和不同数据源类型的更容易的移植性。
四.解决方案
使用数据访问对象(DAO)模式来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便检索和存储数据。
DAO实现了用来操作数据源的访问机制。数据源可以时RDBMS,LDAP,File等。依赖于DAO的业务组件为其客户端使用DAO提供更简单的接口。DAO完全向客户端隐藏了数据源实现细节。由于当低层数据源实现变化时,DAO向客户端提供的接口不会变化,所有该模式允许DAO调整到不同的存储模式,而不会影响其客户端或者业务组件。重要的是,DAO充当组件和数据源之间的适配器。
(按照这个理论,如果我们UPTEL系统使用了DAO模式,就可以无缝的从ORACLE迁移到任何一个RDBMS了。梦想总是很完美的,且看看DAO模式如何实现)
1.结构,图1是表示DAO模式中各种关系的类图。
此主题相关图片如下:
2.参与者和职责
1)BusinessObject(业务对象)
代表数据客户端。正是该对象需要访问数据源以获取和存储数据。
2)DataAccessObject(数据访问对象)
是该模式的主要对象。DataAccessObject抽取该BusinessObject的低层数据访问实现,以保证对数据源的透明访问。BusinessObject也可以把数据加载和存储操作委托给DataAccessObject。
3)DataSource(数据源)
代表数据源实现。数据源可以是各RDBMSR数据库,OODBMS,XML文件等等。
4)valueObject(值对象)
代表用做数据携带着的值对象。DataAccessObject可以使用值对象来把数据返回给客户端。
DataAccessObject也许会接受来自于客户端的数据,其中这些用于更新数据源的数据存放于值对象中来传递。
3.策略
1).自动DAO代码产生策略
因为每个BusinessObject对应于一个特殊的DAO,因此有可能建立BusinessObject,DAO和低层实现(比如RDBMS中的表)之间的关系(映射)。一点这些关系(映射)已经建立,我们就可以编写与应用程序有馆的代码生成的简单工具了(什么?自己写GP程序?用ORM的附带工具自动生成不就完了,最多自己写几个Adapter,牛人就是不同,啥都要自己写...),其中的工具可以产生该应用程序需要的所有DAO代码。
如果DAO需求很复杂,我们可以采用第三方工具,其中这些工具提供对象到RDBMS数据库的关系映射(这里指的是前面提到的ORM工具,全称是Object Relation Mapping,目前成熟的ORM工具有很多:Hibernate,OJB,Torque,TopLink等等)。
这些工具通常包含GUI工具来把业务对象映射到持久性存储对象,并且因而定义中间DAO。一旦这些映射完成,这些工具会自动地生成代码,并且也许会提供其他增值功能,比如结果缓冲、查询缓冲、与应用程序集成,以及与其他第三方产品(比如分布式缓冲)地继承,等等。
(增值服务:Torque提供了结果缓冲,Hibernate提供了对Oracle数据库SQL指令的优化,OJB提供JDO API、OMDB API)
2).数据访问对象的工厂策略
通过调整抽象工厂和工厂方法模式,DAO模式可以达到很高的灵活度。
当低层存储不会随着实现变化而变化时,该策略可以使用工厂方法模式来实现该策略。以产生应用程序需要的大量DAO。图2是这种情况下的类图。
此主题相关图片如下:
当低层存储随着实现变化而变化时,该策略可以使用抽象工厂方法模式而实现。
图3是这种情况下的类图。
此主题相关图片如下:
5.结果
1).启用透明性
业务对象可以是使用数据源,而无须了解该数据源实现的具体细节。访问是透明的,原因是实现被隐藏在DAO的内部。
2).启用更容易的迁移
DAO层使应用程序更加容易地迁移到一个不同的数据库实现。业务对象不了解低层数据实现。因而,该迁移只涉及对DAO层的变化。更进一步说,如果使用工厂策略,则有可能为每一个低层存储实现提供一个具体工厂实现。在这种情况下,迁移到不同的迁移实现意味着给应用程序提供一个新的工厂实现。
3).减少业务对象中代码复杂度
由于DAO管理所有的数据访问复杂性,它可以简化业务对象和其他使用DAO的客户端中的代码。所有与实现有关的代码(比如sql语句)都被包含在DAO中,而不是包含在业务对象中。这样做提高了代码的可读性,已经代码生产效率。
4).把所有的数据访问集中到一个独立的层。
因为所有的数据访问操作现在被委托给DAO,所有单独的数据访问层可以被看作把数据访问实现与应用程序中的其他代码相隔离的。这种集中化使应用程序更容易地维护和管理。
5).不适用于容器管理的持久性
由于EJB容器用容器管理的持久性(CMP)来管理实体bean,该容器会自动地服务所有的持久性存储访问。使用容器管理的实体bean的应用程序不需要DAO层,因为该应用程序服务器透明地提供该功能。然而,当需要组合使用CMP和BMP时,DAO仍旧有用处。
6).添加其他层
DAO会在数据客户端和数据源之间创建其他的对象层,其中该数据源需要被设计和实现以便于权衡该模式的好处。但是选择本方法也会带来额外的开销。
7).需要类层次设计
在使用工厂策略时,我们需要设计和实现具体工厂的层次,以及这些工厂产生的具体产品层次。如果能够确保这种灵活性,则有必要考虑这种额外的工作。这样做会增加设计的复杂性。然而,在实现该工厂策略时,你可以首先考虑工厂方法模式,然后再根据需要过渡到抽象工厂。
六.范例代码
1.实现数据访问对象模式
范例9-4时表示Customer信息的持久性对象的DAO范例代码。当findCustomer()被调用时,CloudscapeCustomerDAO创建一个Customer值对象。
范例9-6是使用DAO的范例代码。
2.实现数据访问对象的工厂策略
1)使用工厂方法模式
2)使用抽象工厂模式
范例代码9-2是CloudscapeDAOFactory的范例代码。
范例代码9-3中的CustomerDAO接口为Customer持久性对象定义了DAO方法,这些接口是被所有具体DAO实现来实现的,比如CloudscapeCustomerDAO、OracleCustomerDAO、已经SybaseCustomerDAO。Account和OrederDAO接口也与此类似。
Example 9.1 Abstract DAOFactory Class
// Abstract class DAO Factory
public abstract class DAOFactory {
// List of DAO types supported by the factory
public static final int CLOUDSCAPE = 1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
...
// There will be a method for each DAO that can be
// created. The concrete factories will have to
// implement these methods.
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountDAO();
public abstract OrderDAO getOrderDAO();
...
public static DAOFactory getDAOFactory(
int whichFactory) {
switch (whichFactory) {
case CLOUDSCAPE:
return new CloudscapeDAOFactory();
case ORACLE :
return new OracleDAOFactory();
case SYBASE :
return new SybaseDAOFactory();
...
default :
return null;
}
}
}
Example 9.2 Concrete DAOFactory Implementation for Cloudscape
// Cloudscape concrete DAO Factory implementation
import java.sql.*;
public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";
// method to create Cloudscape connections
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}
Example 9.3 Base DAO Interface for Customer
// Interface that all CustomerDAOs must support
public interface CustomerDAO {
public int insertCustomer(...);
public boolean deleteCustomer(...);
public Customer findCustomer(...);
public boolean updateCustomer(...);
public RowSet selectCustomersRS(...);
public Collection selectCustomersVO(...);
...
}
Example 9.4 Cloudscape DAO Implementation for Customer
// CloudscapeCustomerDAO implementation of the
// CustomerDAO interface. This class can contain all
// Cloudscape specific code and SQL statements.
// The client is thus shielded from knowing
// these implementation details.
import java.sql.*;
public class CloudscapeCustomerDAO implements
CustomerDAO {
public CloudscapeCustomerDAO() {
// initialization
}
// The following methods can use
// CloudscapeDAOFactory.createConnection()
// to get a connection as required
public int insertCustomer(...) {
// Implement insert customer here.
// Return newly created customer number
// or a -1 on error
}
public boolean deleteCustomer(...) {
// Implement delete customer here
// Return true on success, false on failure
}
public Customer findCustomer(...) {
// Implement find a customer here using supplied
// argument values as search criteria
// Return a value object if found,
// return null on error or if not found
}
public boolean updateCustomer(...) {
// implement update record here using data
// from the customerData value object
// Return true on success, false on failure or
// error
}
public RowSet selectCustomersRS(...) {
// implement search customers here using the
// supplied criteria.
// Return a RowSet.
}
public Collection selectCustomersVO(...) {
// implement search customers here using the
// supplied criteria.
// Alternatively, implement to return a Collection
// of value objects.
}
...
}
Example 9.5 Customer value Object
public class Customer implements java.io.Serializable {
// member variables
int CustomerNumber;
String name;
String streetAddress;
String city;
...
// getter and setter methods...
...
}
Example 9.6 Using a DAO and DAO Factory ?Client Code
...
// create the required DAO Factory
DAOFactory cloudscapeFactory =
DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE);
// Create a DAO
CustomerDAO custDAO =
cloudscapeFactory.getCustomerDAO();
// create a new customer
int newCustNo = custDAO.insertCustomer(...);
// Find a customer object. Get the value object.
Customer cust = custDAO.findCustomer(...);
// modify the values in the value object.
cust.setAddress(...);
cust.setEmail(...);
// update the customer object using the DAO
custDAO.updateCustomer(cust);
// delete a customer object
custDAO.deleteCustomer(...);
// select all customers in the same city
Customer criteria=new Customer();
criteria.setCity("广州");
Collection customersList =
custDAO.selectCustomersVO(criteria);
// returns customersList - collection of Customer
// value objects. iterate through this collection to
// get values.
...
使用JBoss和PostgreSQL-----快速开发EJB和J2EE Web Application
hanqw3 原创 (参与分:20,专家分:30) 发表:2003-8-4 上午11:46 更新:2003-8-4 下午2:49 版本:2.0 阅读:4218次
使用JBoss和PostgreSQL-----快速开发EJB和J2EE Web Application
Developing J2EE Web Application on Jboss and PostgreSQL(chinese version)
作者:Han QW, 转载请指明出处 如有不当之处,敬请指出
先安装JSDK,再安装JBoss.
安装JSDK,必须获得一套对应于用户的操作系统的JDK,
我的安装的文件目录是
WINDOWS2000: d:\s1studio_jdk\j2sdk1.4.1
linux: /root/s1studio_jdk/j2sdk1.4.1
为了用EJB, 需要一个j2ee-1.3.jar或者j2ee-1.2.jar,
如果安装了Sun One Studio 或者 J2EE (www.sun.com )这个文件已经有.
把这个文件放在classpath路径上.
或者使用jboss-j2ee.jar, 安装JBoss后在$JBoss\client中可找到.
建议安装Sun One Studio, 用Sun One Studio编译JAVA源程序,
不用设置classpath, 省去不少过程.
安装JBoss:
把JBoss的压缩包解开,放在任一目录上,
我的安装的文件目录是
/dose/jboss-3.0.4_tomcat-4.1.12 (REDHAT8.0)
E:\jboss-3.0.4_tomcat-4.1.12 (WINDOWS2000)
WINDOWS2000, linux共用同一套JBoss.
配置JBoss:
启动JBoss需要执行一个脚本文件:
linux:run.sh
WINDOWS对应的是:run.bat
(1)
在JBoss\bin\run.bat (for Windows)开头插入一行
set JAVA_HOME = d:\s1studio_jdk\j2sdk1.4.1
在JBoss\bin\run.sh (for Linux)开头插入一行
JAVA_HOME="/root/s1studio_jdk/j2sdk1.4.1"
或者
(2)设置系统环境变量JAVA_HOME,指向JDK
运行JBoss, run.sh或者run.bat
当看到启动JBoss的信息时,说明启动了.
服务器简单的测试:
JBoss默认的WEB端口为8080,我们可以在打开一个浏览器输入地址
http://localhost:8080/jmx-console
当在浏览器看到JBoss的信息时,说明安装配置JBoss成功了.
建立下面的目录和文件(注意大小写).
FIRST.EAR
|
|-----META-INF (application.xml)
|
|-----First.jar
| |-----META-INF (ejb-jar.xml,jboss.xml)
| `-----Dev
| |-----First(FirstSession.java, FirstSessionHome.java, FirstSessionBean.java)
| |-----Delegate(NewDelegate.java)
| `-----Dao(MysqlDao.java)
|
`-----First.war(index.jsp)
|
`-----WEB-INF (jboss-web.xml, web.xml)
|-----classes
`-----lib
/*
**
**MysqlDao.java
**
*/
package Dev.Dao;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MysqlDao {
public Connection getConnection() throws Exception {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/PostgresDS");
Connection conn = null;
Statement stmt = null;
try {
conn = ds.getConnection();
} catch (SQLException sqlEx) {
System.out.println("Error connect to pool.");
}
return conn;
}
public String getName(String id) throws Exception {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String name = "";
try {
conn = getConnection();
if ( conn !=null )System.out.println("Get conecttion. "+ conn.toString());
stmt = conn.createStatement();
if ( stmt !=null )System.out.println("Get Statement. "+ stmt.toString());
String sql = "SELECT * from users where id = '"+id+"'";
System.out.println("Sql from getId(): "+sql);
rs = stmt.executeQuery(sql);
if ( rs !=null )System.out.println("Get result. ");
if (rs.next()){
name = rs.getString("name");
}
} catch (Exception sqlEx) {
System.out.println("Error from getName().");
System.out.println("Error from DAO.getName() :" + sqlEx.getMessage());
}finally {
if (conn != null) {
try { conn.close(); } catch (Exception sqlEx) { }
}
}
return name;
}
public String getCountry(String id) throws Exception {
Connection conn = null;
Statement stmt = null;
String name = "";
try {
conn = getConnection();
stmt = conn.createStatement();
String sql = "SELECT * from users where id = '"+id+"'";
System.out.println("Sql from getCountry(): "+sql);
java.sql.ResultSet rs = stmt.executeQuery(sql);
if (rs.next())
{
name = rs.getString("Country");
}
} catch (SQLException sqlEx) {
System.out.println("Error from getCountry().");
}finally {
if (conn != null) {
try { conn.close(); } catch (Exception sqlEx) { }
}
}
return name;
}
}
/*
**
**NewDelegate.java
**
*/
package Dev.Delegate;
import java.lang.*;
import Dev.First.*;
public class NewDelegate {
Dev.First.FirstSession bean = null;
public NewDelegate( ){
try {
javax.naming.InitialContext ctx = new javax.naming.InitialContext();
Object objref = ctx.lookup("ejb/FirstSession");
Dev.First.FirstSessionHome testBean = (Dev.First.FirstSessionHome)
javax.rmi.PortableRemoteObject.narrow
(objref,Dev.First.FirstSessionHome.class);
bean = testBean.create();
System.out.println("From JSP");
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
}
public String Welcome() {
String msg = "";
try {
msg = bean.Welcome();
} catch (Exception NamingException) {
NamingException.printStackTrace();
}
return msg;
}
public String getName(String id) {
String name = "";
try {
name = bean.getName(id);
} catch (Exception NamingException) { NamingException.printStackTrace();}
return name;
}
public String getCountry(String id) {
String country = "";
try {
country = bean.getCountry(id);
} catch (Exception NamingException) { NamingException.printStackTrace();}
return country;
}
}
/*
**
**FirstSession.java
**
*/
package Dev.First;
import java.lang.*;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public interface FirstSession extends javax.ejb.EJBObject{
public String Welcome() throws java.rmi.RemoteException;
public String getName(String id) throws java.rmi.RemoteException;
public String getCountry(String id) throws java.rmi.RemoteException;
}
/*
**
**FirstSessionHome.java
**
*/
package Dev.First;
import java.lang.*;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public interface FirstSessionHome extends javax.ejb.EJBHome{
public FirstSession create() throws javax.ejb.CreateException, java.rmi.RemoteException;
}
/*
**
**FirstSessionBean.java
**
*/
package Dev.First;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class FirstSessionBean implements SessionBean{
public void ejbCreate() throws CreateException {
}
public String Welcome(){
String msg="Hello! This My Session Bean From Jboss.";
System.out.println(msg);
return msg;
}
public String getName(String id){
String name = "";
System.out.println("From bean before getName :"+ name);
try{
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
name = dao.getName(id);
System.out.println("From bean after getName :"+ name);
}catch(Exception e){ System.out.println(e.getMessage());}
return name;
}
public String getCountry(String id){
String country = "";
try{
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
country = dao.getCountry(id);
}catch(Exception e){ }
return country;
}
public void setSessionContext( SessionContext aContext ) throws EJBException {
}
public void ejbActivate() throws EJBException {
}
public void ejbPassivate() throws EJBException {
}
public void ejbRemove() throws EJBException {
}
}
/*Don't put the following lines into index.jsp
**
**index.jsp
**
*/Don't put the above lines into index.jsp
<%@page language="java" %>
<%
String msg = "";
String msg1 = "";
Dev.Delegate.NewDelegate nn = new Dev.Delegate.NewDelegate();
if (request.getParameter("id") != null &&
request.getParameter("id") != ""&&
!request.getParameter("id").equals("")){
String id = request.getParameter("id");
String name = "";
Dev.Dao.MysqlDao dao = new Dev.Dao.MysqlDao();
name = nn.getName(id); //access database through session bean
//name = dao.getName(id); //access database directly
if(name!= null && !name.equals("")){
msg1 ="Welcome " + name +" ! You are from "+ dao.getCountry(id)+ " .";
}else{
msg1 ="Please Check Your ID. : " + id;
}
}
msg = nn.Welcome() ;
%>
<%= msg %>
<%=(msg1 == "")? "":msg1 + "
Connect to Database OK." %>
不要将此以上5行存入文件, 下同.
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
"http://www.jboss.org/j2ee/dtd/jboss-web.dtd">
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
编译JAVA源程序,生成class文件.
进入JAVA源程序目录, 运行:
javac -classpath %classpath%;%jboss%\server\default\deploy\First.ear\First.jar *.java
或者
javac -classpath %jboss%\server\default\deploy\First.ear\First.jar;%jboss%\client\jboss-j2ee.jar *.java
Copy 目录First.ear to jboss\server\default\deploy.
打开浏览器输入地址 http://localhost:8080/First
到此, 在浏览器看到: Hello! This My Session Bean From Jboss.
说明这个EJB工作了.
如果按按钮, 没反应或出错. 原因没安装配置数据库, 下面安装配置Postgres数据库
For Windows2000
下载 PgSQL731wina1.exe (http://www.postgresql.org),
Finally you will see the next line, you need enter the password for Administrator
最后你将看下一个行,你必须为用户Administrator输入password.
********************
Enter password of user `.\Administrator':123456
********************
记下此password, 我的口令是123456.
从开始菜单 > Programm > PostgresSQL > Adjust PostgresSQL Configuration file
它将在Wordpad中打开PostgresSQL Configuration文件, 找到下列行,
#
# Connection Parameters
#
#tcpip_socket = false
#ssl = false
#max_connections = 32
#superuser_reserved_connections = 2
#port = 5432
修改编辑:
#
# Connection Parameters
#
tcpip_socket = true
#ssl = false
#max_connections = 32
#superuser_reserved_connections = 2
port = 5432
接着,保存文件.
起动PostgresSQL服务器:
开始菜单>Programm>PostgresSQL>Utilies>Start PostgresSQL server
起动命令行:
开始菜单>Programm>PostgresSQL>Utilies>Command Shell
执行下列命令,准备数据,
Administrator@SAN /
$ dir
$ cd bin
$ createdb test
$ psql test
test=# create table users
test-# (name varchar(20),
test(# id varchar(20),
test(# country varchar(20));
test=# insert into users values ('Sam', '123', 'China');
test=# insert into users values ('Tom', '321', 'USA');
test=# insert into users values ('Sean', '231', 'France');
test=# select * from users;
name | id | country
------+-----+---------
Sam | 123 | China
Tom | 321 | USA
Sean | 231 | France
(3 rows)
test=#
到此, 数据准备就绪.
For RedHat:
以root登陆, 执行下列命令,准备数据,
mkdir /usr/local/pgsql/data
chown postgres /usr/local/pgsql/data
su - postgres
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
Open and edit /usr/local/pgsql/data/pg_hba.conf
local all trust
host all 127.0.0.1 255.255.255.255 trust
just delete #, and save.
[root@localhost root]# su - postgres
-bash-2.05b$ /usr/bin/postmaster -i -D /usr/local/pgsql/data >logfile 2>&1 &
-bash-2.05b$ /usr/bin/createdb test
-bash-2.05b$ /usr/local/pgsql/bin/psql test
test=# .......the following same as Windows2000
到此, 数据准备就绪.
执行shutdown.bat or shutdown.sh, 停止Jboss Server.
找到JDBC drive.
为了在Jboss中使用连接池,需要拷贝jdbc drive 到Jboss/server/default/deploy , 在linux 我们能找到/usr/share/pgsql/pgjdbc2.jar,在wondows2000,我们能找到PostgreSQL\usr\share\postgresql\java\postgresql.jar
把其中之一复制到Jboss/server/default/deploy
配置Jboss
(1) 复制 $Jboss/examples/jca/postgres-service.xml 到 $Jboss/server/default/deploy/
(2) 打开编辑Jboss/server/default/deploy/postgres-service.xml
In my example, set Username Administrator, password 123456 for windows 2000
set Username Postgres, no password for Linux.
在我的例子中,
windows2000, 用户:Administrator,password:123456
Linux(RH8.0), 用户:Postgres, 没有password
因为PostgresSQL和windows2000使用不同的default用户名,所以在linux和window2000中这文件不同.当然,你可以加相同的PostgresSQL用户名和password在linux和window2000中, 这样这文件就相同了.
保存文件.
(3) 打开编辑 $Jboss/server/default/conf/standardjbosscmp-jdbc.xml
找到:
加入:
保存文件.
(4) open and edit $Jboss/server/default/conf/standardjaws.xml
找到:
加入:
------
回复此文章 | edit | hide
回复主题:Re:dao技术 | 作者: haohao | 军衔:六级军士 | 发表时间:2004-07-27 10:20:33
=============Student.java==========
import java.sql.*;
public class Student implements java.io.Serializable{
private String id;
private String name;
private Date birthday;
public Student(){}
public Student(String id, String name, Date birthday){
this.id = id;
this.name = name;
this.birthday = birthday;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
}
=================Course.java======================
public class Course implements java.io.Serializable{
private String id;
private String name;
private String description;
public Course() {}
public Course(String id, String name, String description){
this.id = id;
this.name = name;
this.description = description;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name ) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}
==============SMdao.java==================
import java.sql.*;
public interface SMdao {
public Student createStudent(String id, String name, Date birthday);
publc Course createCourse(String id, String name, String description);
public Student findStudent(String id);
public Course findCourse(String id);
public void clean();
}
==============FileSMdaoImpl.java==============
import java.util.Properties;
import java.sql.*;
import java.io.*;
public class FileSMdaoImpl implements SMdao {
private Properties pro;
private final static String SFILE_URL = "student.file.url";
private final static String CFILE_URL = "course.file.url";
public FileSMdaoImpl(Properties pro){
this.pro = pro;
}
public Student createStudent(String id, String name, Date birthday) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Student stu = null;
try {
fos = new FileOutputStream(pro.getProperty(FILE_URL), true);
oos = new ObjectOutputStream(fos);
stu = new Student(id, name, birthday);
oos.writeObject(stu);
} catch(Exception e) { stu = null; }
finally{
try { if(oos != null) oos.close(); } catch(Exception e){}
try { if(fos != null) oos.close(); } catch(Exception e) {}
}
return stu;
}
public Course createCourse(String id, String name, String description){
return null;
}
public Student findStudent(String id) {
return null;
}
public Course findCourse(String id) {
return null;
}
public void clean() {}
}
==============DBSMdaoImpl.java==============
import java.sql.*;
import java.util.Properties;
public class DBSMdaoImpl implements SMDao {
private Connection con;
private final static String DBDRV = "db.driver";
private final static String DBURL = "db.url";
private final static String DBUSER = "db.user";
private final static String DBPASSWD = "db.password";
public DBSMdaoImpl(Properties pro) {
try {
Class.forName(pro.getProperty(DBDRV));
String user = pro.getProperty(DBUSER);
String passwd = pro.getProperty(DBPASSWD);
if(user != null)
con = DriverManager.getConnection(pro.getProperty(DBURL),
user, passwd);
else
con = DriverManager.getConnection(pro.getProperty(DBURL));
} catch(Exception e){}
}
public Student createStudent(String id, String name, Date birtyday) {
if(con == null) return null;
Student stu = null;
PreparedStatement stm = null;
try {
stm = con.prepareStatement("insert into student(id, name, birthday) " +
"values(?, ?, ?)");
stm.setString(1, id);
stm.setString(2, name);
stm.setDate(3, birthday);
if(stm.executeUpdate() > 0)
stu = new Student(id, name, birthday);
}catch(Exception e){}
finally{
try {if(stm != null) stm.close();}
catch(Exception e) {}
}
return stu;
}
public Course createCourse(String id, String name, String desc) { return null; }
public Student findStudent(String id) { return null; }
public Course findCourse(String id) { return null; }
public void clean() {
try {
if(con != null) con.close();
}catch(Exception e) {}
}
}
===============SMdaoFactory.java===============
import java.util.*;
public class SMdaoFactory {
Properties pro;
public static final String TYPE_FILE = "file";
public static final String TYPE_DB = "database";
private String type;
private static SMdaoFactory factory;
static{ factory = new SMdaoFactory();}
private SMdaoFactory() {
}
public static SMdaoFactory newInstance() { return factory; }
public void setType(String type) { this.type = type; }
public void setProperties(Properties pro) { this.pro = pro; }
public SMdao createSMdao() {
if(type.equals(TYPE_FILE))
return new FileSMdaoImpl(pro);
else
return new DBSMdaoImpl(pro);
}
}
=================Main.java=========================================
import java.io.*;
import java.util.*;
import java.sql.*;
public class Main{
public static void main(String args[]){
Properties pro = new Properites();
try {
pro.load(Main.class.getResourceAsStream("conf.properties");
}catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
SMdaoFactory factory = SMdaoFactory.newInstance();
factory.setType(SMdaoFactory.TYPE_DB);
factory.setProperties(pro);
SMdao dao = factory.createSMdao();
GregorainCalendar calendar = new GregorainCalendar();
calendar.set(Calendar.YEAR, 1975);
calendar.set(Calendar.MONTH, 2);
calendar.set(Calendar.DAY_OF_MONTH, 21);
java.sql.Date birthday = new java.sql.Date(calendar.getTimeInMills());
Student stu = dao.createStudent("12345", "George", birthday);
}
}
==============conf.properties===================
db.driver=COM.pointbase.jdbc.jdbcUniversalDriver
db.url=jdbc:pointbase:server://george/sample
db.user=pbpulic
db.password=pbpublic
student.file.url=student
course.file.url=course
------
回复此文章 | edit | hide
回复主题:Re:Re:dao技术 | 作者: haohao | 军衔:六级军士 | 发表时间:2004-07-27 10:23:32
http://www.matrix.org.cn/article/853.html
免费注册
用户登陆
帮助中心
JAVA首页 Matrix动态 Java专栏 Java下载 Java网站 用户中心 开源项目 JAVA论坛
您现在位于: 首页 → Java专栏---浏览技术文章
读《J2EE核心模式》(DAO模式)
2004年4月7日 作者:martin Matrix-与Java共舞
读《J2EE核心模式》(DAO模式)
from Martin的blog: http://www.matrix.org.cn/blog/martin/
很多的J2EE应用程序需要使用持久性数据(数据库、文件等)。不同的程序,持久性存储是各不相同的,并且用来访问这些不同的持久性存储机制的API也有很大的不同。如果应用程序要在不同的持久性存储间迁移,这些访问特定持久存储层的代码将面临重写。
如何解决这个问题?且看"DAO模式"
数据访问对象(Data Acess Object) 模式
一.环境
根据数据源不同,数据访问也不同。根据存储的类型(关系数据库、面向对象数据库、文件等等)和供应商实现不同,持久性存储(比如数据库)的访问差别也很大。
二.问题
许多真是的J2EE应用程序需要在一定程度上使用持久性数据。对于许多应用程序,持久性存储是使用不同的机制实现的,并且用来访问这些不同的持久性存储机制的API也有很大的不同。
比如,应用程序使用实体bean(这里应该是指BMP的bean,CMP的bean已大大降低了与RDBMS的耦合)的分布式组件来表示持久性数据,或者使用JDBC API来访问驻留在某关系数据库管理系统(RDBMS)中的数据,这些组件中包含连接性性和数据访问代码会引入这些组件与数据源实现之间的紧密耦合。组件中这类代码依赖性使应用程序从某种数据源迁移到其他种类的数据源将变得非常麻烦和困难。当数据源变化时,组件也需要改变,以便于能够处理新类型的数据源。
(举个例子来说,我们UPTEL系统是使用JDBC API对 ORACLE数据库进行连接和数据访问的,这些JDBC API与SQL语句散布在系统中,当我们需要将UPTEL迁移到其他RDBMS时,比如曾经迁移到INFORMIX,就面临重写数据库连接和访问数据的模块。)
三.作用力
1.诸如bean管理的实体bean、会话bean、servlet等组件往往需要从持久性存储数据源中检索数据,以及进行数据存储等操作。
2.根据产品供应商的不同,持久性存储API差别也很大,这些API和其能力同样根据存储的类型不同也有差别,这样存在以下缺点,即访问这些独立系统的API很不统一。
3.组件需要透明于实际的持久性存储或者数据源实现,以便于提供到不同供应商产品、不同存储类型和不同数据源类型的更容易的移植性。
四.解决方案
使用数据访问对象(DAO)模式来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便检索和存储数据。
DAO实现了用来操作数据源的访问机制。数据源可以时RDBMS,LDAP,File等。依赖于DAO的业务组件为其客户端使用DAO提供更简单的接口。DAO完全向客户端隐藏了数据源实现细节。由于当低层数据源实现变化时,DAO向客户端提供的接口不会变化,所有该模式允许DAO调整到不同的存储模式,而不会影响其客户端或者业务组件。重要的是,DAO充当组件和数据源之间的适配器。
(按照这个理论,如果我们UPTEL系统使用了DAO模式,就可以无缝的从ORACLE迁移到任何一个RDBMS了。梦想总是很完美的,且看看DAO模式如何实现)
1.结构,图1是表示DAO模式中各种关系的类图。
此主题相关图片如下:
2.参与者和职责
1)BusinessObject(业务对象)
代表数据客户端。正是该对象需要访问数据源以获取和存储数据。
2)DataAccessObject(数据访问对象)
是该模式的主要对象。DataAccessObject抽取该BusinessObject的低层数据访问实现,以保证对数据源的透明访问。BusinessObject也可以把数据加载和存储操作委托给DataAccessObject。
3)DataSource(数据源)
代表数据源实现。数据源可以是各RDBMSR数据库,OODBMS,XML文件等等。
4)valueObject(值对象)
代表用做数据携带着的值对象。DataAccessObject可以使用值对象来把数据返回给客户端。
DataAccessObject也许会接受来自于客户端的数据,其中这些用于更新数据源的数据存放于值对象中来传递。
3.策略
1).自动DAO代码产生策略
因为每个BusinessObject对应于一个特殊的DAO,因此有可能建立BusinessObject,DAO和低层实现(比如RDBMS中的表)之间的关系(映射)。一点这些关系(映射)已经建立,我们就可以编写与应用程序有馆的代码生成的简单工具了(什么?自己写GP程序?用ORM的附带工具自动生成不就完了,最多自己写几个Adapter,牛人就是不同,啥都要自己写...),其中的工具可以产生该应用程序需要的所有DAO代码。
如果DAO需求很复杂,我们可以采用第三方工具,其中这些工具提供对象到RDBMS数据库的关系映射(这里指的是前面提到的ORM工具,全称是Object Relation Mapping,目前成熟的ORM工具有很多:Hibernate,OJB,Torque,TopLink等等)。
这些工具通常包含GUI工具来把业务对象映射到持久性存储对象,并且因而定义中间DAO。一旦这些映射完成,这些工具会自动地生成代码,并且也许会提供其他增值功能,比如结果缓冲、查询缓冲、与应用程序集成,以及与其他第三方产品(比如分布式缓冲)地继承,等等。
(增值服务:Torque提供了结果缓冲,Hibernate提供了对Oracle数据库SQL指令的优化,OJB提供JDO API、OMDB API)
2).数据访问对象的工厂策略
通过调整抽象工厂和工厂方法模式,DAO模式可以达到很高的灵活度。
当低层存储不会随着实现变化而变化时,该策略可以使用工厂方法模式来实现该策略。以产生应用程序需要的大量DAO。图2是这种情况下的类图。
此主题相关图片如下:
当低层存储随着实现变化而变化时,该策略可以使用抽象工厂方法模式而实现。
图3是这种情况下的类图。
此主题相关图片如下:
5.结果
1).启用透明性
业务对象可以是使用数据源,而无须了解该数据源实现的具体细节。访问是透明的,原因是实现被隐藏在DAO的内部。
2).启用更容易的迁移
DAO层使应用程序更加容易地迁移到一个不同的数据库实现。业务对象不了解低层数据实现。因而,该迁移只涉及对DAO层的变化。更进一步说,如果使用工厂策略,则有可能为每一个低层存储实现提供一个具体工厂实现。在这种情况下,迁移到不同的迁移实现意味着给应用程序提供一个新的工厂实现。
3).减少业务对象中代码复杂度
由于DAO管理所有的数据访问复杂性,它可以简化业务对象和其他使用DAO的客户端中的代码。所有与实现有关的代码(比如sql语句)都被包含在DAO中,而不是包含在业务对象中。这样做提高了代码的可读性,已经代码生产效率。
4).把所有的数据访问集中到一个独立的层。
因为所有的数据访问操作现在被委托给DAO,所有单独的数据访问层可以被看作把数据访问实现与应用程序中的其他代码相隔离的。这种集中化使应用程序更容易地维护和管理。
5).不适用于容器管理的持久性
由于EJB容器用容器管理的持久性(CMP)来管理实体bean,该容器会自动地服务所有的持久性存储访问。使用容器管理的实体bean的应用程序不需要DAO层,因为该应用程序服务器透明地提供该功能。然而,当需要组合使用CMP和BMP时,DAO仍旧有用处。
6).添加其他层
DAO会在数据客户端和数据源之间创建其他的对象层,其中该数据源需要被设计和实现以便于权衡该模式的好处。但是选择本方法也会带来额外的开销。
7).需要类层次设计
在使用工厂策略时,我们需要设计和实现具体工厂的层次,以及这些工厂产生的具体产品层次。如果能够确保这种灵活性,则有必要考虑这种额外的工作。这样做会增加设计的复杂性。然而,在实现该工厂策略时,你可以首先考虑工厂方法模式,然后再根据需要过渡到抽象工厂。
六.范例代码
1.实现数据访问对象模式
范例9-4时表示Customer信息的持久性对象的DAO范例代码。当findCustomer()被调用时,CloudscapeCustomerDAO创建一个Customer值对象。
范例9-6是使用DAO的范例代码。
2.实现数据访问对象的工厂策略
1)使用工厂方法模式
2)使用抽象工厂模式
范例代码9-2是CloudscapeDAOFactory的范例代码。
范例代码9-3中的CustomerDAO接口为Customer持久性对象定义了DAO方法,这些接口是被所有具体DAO实现来实现的,比如CloudscapeCustomerDAO、OracleCustomerDAO、已经SybaseCustomerDAO。Account和OrederDAO接口也与此类似。
Example 9.1 Abstract DAOFactory Class
// Abstract class DAO Factory
public abstract class DAOFactory {
// List of DAO types supported by the factory
public static final int CLOUDSCAPE = 1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
...
// There will be a method for each DAO that can be
// created. The concrete factories will have to
// implement these methods.
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountDAO();
public abstract OrderDAO getOrderDAO();
...
public static DAOFactory getDAOFactory(
int whichFactory) {
switch (whichFactory) {
case CLOUDSCAPE:
return new CloudscapeDAOFactory();
case ORACLE :
return new OracleDAOFactory();
case SYBASE :
return new SybaseDAOFactory();
...
default :
return null;
}
}
}
Example 9.2 Concrete DAOFactory Implementation for Cloudscape
// Cloudscape concrete DAO Factory implementation
import java.sql.*;
public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";
// method to create Cloudscape connections
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}
Example 9.3 Base DAO Interface for Customer
// Interface that all CustomerDAOs must support
public interface CustomerDAO {
public int insertCustomer(...);
public boolean deleteCustomer(...);
public Customer findCustomer(...);
public boolean updateCustomer(...);
public RowSet selectCustomersRS(...);
public Collection selectCustomersVO(...);
...
}
Example 9.4 Cloudscape DAO Implementation for Customer
// CloudscapeCustomerDAO implementation of the
// CustomerDAO interface. This class can contain all
// Cloudscape specific code and SQL statements.
// The client is thus shielded from knowing
// these implementation details.
import java.sql.*;
public class CloudscapeCustomerDAO implements
CustomerDAO {
public CloudscapeCustomerDAO() {
// initialization
}
// The following methods can use
// CloudscapeDAOFactory.createConnection()
// to get a connection as required
public int insertCustomer(...) {
// Implement insert customer here.
// Return newly created customer number
// or a -1 on error
}
public boolean deleteCustomer(...) {
// Implement delete customer here
// Return true on success, false on failure
}
public Customer findCustomer(...) {
// Implement find a customer here using supplied
// argument values as search criteria
// Return a value object if found,
// return null on error or if not found
}
public boolean updateCustomer(...) {
// implement update record here using data
// from the customerData value object
// Return true on success, false on failure or
// error
}
public RowSet selectCustomersRS(...) {
// implement search customers here using the
// supplied criteria.
// Return a RowSet.
}
public Collection selectCustomersVO(...) {
// implement search customers here using the
// supplied criteria.
// Alternatively, implement to return a Collection
// of value objects.
}
...
}
Example 9.5 Customer value Object
public class Customer implements java.io.Serializable {
// member variables
int CustomerNumber;
String name;
String streetAddress;
String city;
...
// getter and setter methods...
...
}
Example 9.6 Using a DAO and DAO Factory ?Client Code
...
// create the required DAO Factory
DAOFactory cloudscapeFactory =
DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE);
// Create a DAO
CustomerDAO custDAO =
cloudscapeFactory.getCustomerDAO();
// create a new customer
int newCustNo = custDAO.insertCustomer(...);
// Find a customer object. Get the value object.
Customer cust = custDAO.findCustomer(...);
// modify the values in the value object.
cust.setAddress(...);
cust.setEmail(...);
// update the customer object using the DAO
custDAO.updateCustomer(cust);
// delete a customer object
custDAO.deleteCustomer(...);
// select all customers in the same city
Customer criteria=new Customer();
criteria.setCity("广州");
Collection customersList =
custDAO.selectCustomersVO(criteria);
// returns customersList - collection of Customer
// value objects. iterate through this collection to
// get values.
...
haohao
2004-07-31 21:18:55
评论:0
阅读:1936
引用:0
