西北望·射天狼 2006-8-28 20:57
[原创]MyEclipse下Hibernate入门级应用~~
所谓的对象-关系映射模式(ORM),在单个组件中负责所有实体域对象的持久化封装数据访问细节。由于目前常用的是关系数据库系统,欲将面向对象编程思想里的“对象”(常指实体域对象)永久保存到数据库中,就需要使用到对象持久化。对象持久化的模式除ORM以外,还有主动域对象模式、JDO模式、CMP模式(J2EE中常用)等等。而Hibernate就是最常用的ORM中间件之一。
应用程序可以直接通过Hibernate API访问数据库。Hibernate API中的装口可分为以下几类:
· 提供访问数据库的操作的接口。这些接口包括:Session、Transaction和Qurey接口。
· 用于配置Hibernate的接口:Configuration
· 回调接口,使应用程序接受Hibernate内部发生的事件并做出相关的回应。包括:Interceptor、Liftcyclte和Validateble接口。
· 用于扩展hibernate的功能的接口。如UserType、CompositeUserType和IdentifierGenerator接口。
Hibernate内部封装了JDBC、JTA(Java Transaction API)和JNDI(Java Naming and Directory Interface)。JDBC提供底层的数据访问操作,只要用户提供了相应的JDBC驱动程序,Hibernate可以访问任何一个数据库系统。JNDI和JTA使Hibernate能够和J2EE应用服务器集成。
下面是一个自己在学Hibernate时的第一个简单应用,直接在myeclipse下完成的:
目的:学习简单的使用Hibernate将对象持久化到数据库.
过程如下:
建立数据库和相关的表。
在myeclipse database explorer下配置好数据库设置(非必须但是事先配置好的话,后面的数据映射就会方便很多)
在elipse下建立了一个web project,在项目上add Hibernate Capabilites..在由myeclipse自动生成好的hibernate.cfg.xml里配置好。
这里我的hibernate.cfg.xml配置文件如下:
[qutoe]<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/hibernate_test
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="myeclipse.connection.profile">
Mysql JDBC
</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="show_sql">true</property>
<mapping resource="Customer.hbm.xml" /><!--这一行后来加上的-->
</session-factory>
</hibernate-configuration>[/quote]
创建欲持久化的类Customer
在这个类里面包含与数据库相应表直接相关的一些属性,以及相应的getXXXX()和setXXXX()方法(很类似于javabean)。
生成与Customer映射的Customer.hbm.xml。在这里可以在myeclipse database explorer(Hibernate Reverse Engineering...)下去创建生成。
写一个处理方法就可以将Customer持久化到数据库里了~
比如已经初始化了一个Customer对象,就可以使用以下代码将它持久化到数据库:
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(c);
tx.commit();
session.close();
西北望·射天狼 2006-8-29 08:19
Hibernate的初始化:
1)创建一个Configuration类的实例。他的构造方法的把默认文件路径下的配置文件中的配置信息读入到内存。
2)调用Configuration类的configure()把配置文件中的确良Customer.hbm.xml文件映射信息读入到内存中。
3)调用Configuration类的buildSessionFactory()创建一个SessionFactory实例并把Configuration对象包含的所有配置信息拷贝到SessionFactory对象缓存中。SessionFactory代表一个数据存储源。
然后,就可以调用SessionFactory实例的openSession()来获得Session实例,再通过它执行访问数据库的操作。
Session接口提供了操纵数据库的各种方法,如:
save():把对象保存数据库中。
update():更新数据库中的java对象
delete():把Java对象中数据库中删除
load():从数据库中加载Java对象
find():从数据库中查询java对象
通常将每一个Session实例和一个数据库事务绑定。
西北望·射天狼 2006-8-29 09:18
[转贴]
在 struts+ hibernate 这种结构中,是不应该把Hibernate产生的PO直接传递给JSP的,不管他是Iterator,还是List,这是一个设计错误。
我来谈谈在J2EE架构中各层的数据表示方法:
Web层的数据表示是FormBean,数据来源于HTML Form POST
业务层的数据表示是VO
持久层的数据表示是PO,其数据来源于数据库,持久层的数据表示例如CMP。在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内,而不应该扩散到其它层,这样可以降低层间的耦合性,提高J2EE架构整体的可维护性和可扩展性。比如说Web层的逻辑进行了修改,那么只需要修改FormBean的结构,而不需要触动业务层和持久层的代码修改。同样滴,当数据库表进行了小的调整,那么也只需要修改持久层数据表示,而不需要触动业务层代码和Web层代码。
不过由于Hibernate的强大功能,例如动态生成PO,PO的状态管理可以脱离Session,使得在应用了Hibernate的J2EE框架中,PO完全可以充当VO,因此我们下面把PO和VO合并,统称为PO。
先来谈谈ActionFormBean和持久层的PO之间的重大区别:
在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多人干脆就是用ActionFormBean来充当PO,于是ActionFormBean从JSP页面到Servlet控制层再到业务层,然后穿过持久层,最后一直映射到数据库表。真是一竿子捅到了底!
但是在复杂的应用中,ActionFormBean和PO是分离的,他们也不可能一样。ActionFormBean是和网页里面的Form表单一一对应的,Form里面有什么元素,Bean里面就有什么属性。而PO和数据库表对应,因此如果数据库表不修改,那么PO也不会修改,如果页面的流程和数据库表字段对应关系不一致,那么你又如何能够使用ActionFormBean来取代PO呢?
比如说吧,用户注册页面要求注册用户的基本信息,因此HTML Form里面包含了基本信息属性,于是你需要一个ActionFormBean来一一对应(注意:是一一对应),每个Bean属性对应一个文本框或者选择框什么的。
而用户这个持久对象呢?他的属性和ActionFormBean有什么明显不同呢?他会有一些ActionFormBean所没有的集合属性,比如说用户的权限属性,用户的组属性,用户的帖子等等。另外还有可能的是在ActionFormBean里面有3个属性,分别是用户的First Name, Middle Name, Last Name,而在我的User这个持久对象中就是一个 Name 对象属性。
假设我的注册页面原来只要你提供First Name,那么ActionFormBean就这一个属性,后来我要你提供全名,你要改ActionFormBean,加两个属性。但是这个时候PO是不应该修改滴,因为数据库没有改。
那么在一个完整的J2EE系统中应该如何进行合理的设计呢?
JSP(View) ---> Action Form Bean (Module) ---> Action(Control)
Action Form Bean是Web层的数据表示,它和HTML页面Form对应,只要Web页面的操作流程发生改变,它就要相应的进行修改,它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵连到业务层和持久层的大面积的代码进行修改,对于软件的可维护性和可扩展性而言,是一个灾难,Actiont就是他的边界,到此为止!
Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB
而PO则是业务层和持久层的数据表示,它在业务层和持久层之间进行流动,他不应该也不能被传递到Web层的View中去,而ActionServlet就是他的边界,到此为止!
然后来看一看整个架构的流程:
当用户通过浏览器访问网页,提交了一个页面。于是Action拿到了这个FormBean,他会把FormBean属性读出来,然后构造一个PO对象,再调用业务层的Bean类,完成了注册操作,重定向到成功页面。而业务层Bean收到这个PO对象之后,调用DAO接口方法,进行持久对象的持久化操作。
当用户查询某个会员的信息的时候,他用全名进行查询,于是Action得到一个UserNameFormBean包括了3个属性,分别是first name, middle name, last name,然后Action把UserNameFormBean的3个属性读出来,构造Name对象,再调用业务Bean,把Name对象传递给业务Bean,进行查询。
业务Bean取得Name(注意: Name对象只是User的一个属性)对象之后调用DAO接口,返回一个User的PO对象,注意这个User不同于在Web层使用的UserFormBean,他有很多集合属性滴。然后业务Bean把User对象返回给Action。
Action拿到User之后,把User的基本属性取出(集合属性如果不需要就免了),构造UserFormBean,然后把UserFormBean request.setAttribute(...),然后重定向到查询结果页面。
查询页面拿到request对象里面的ActionFormBean,自动调用tag显示之。
总结:
Form Bean 是Web层的数据表示,他不能被传递到业务层;PO是持久层的数据表示,在特定情况下,例如Hibernate中,他可以取代VO出现在业务层,但是不管PO还是VO都必须限制在业务层内使用,最多到达Web层的Control,绝不能被扩散到View去。
Form Bean 和PO之间的数据转化是在Action中进行滴。
西北望·射天狼 2006-8-29 15:15
myeclipse+struts+hibernate的简单应用~
1)首先创建一个web project,为其加上struts组件。
2)创建一个struts form、action和jsp页面。设置配置文件。可以直接在无hibernate的环境下运行此web应用。
3)为了实现表现层、业务层、持久层的分离,建立一个欲持久化的BusinessBean,包含一系列属性和相应的getter和setter。
4)引入hibernate组件,配置好数据映射文件。(这里要注意配置文件里的类路径,记得加上包的名字)
5)建立一个用于处理数据库操作的类
6)在Action里处理业务逻辑并将处理结果返回到web browse
西北望·射天狼 2006-8-29 17:23
Hibernate对象关系映射详解
持久化类使用JavaBean风格,为需要被访问的属性提供getXXXX()和setXXXX()方法。
Java应用程序不能访问持久化类的private类型的getXXXX()和setXXXX()方法,而Hibernate没有这个限制。
可以在持久化类的访问方法中加入程序逻辑。
比如说:
...
private String firstName;
private String lastName;
public String getName(){
return firstName+ "" +lastName;
}
public void setName(String name){
StringTokenizer t = new StringTokenizer(name);
firstName = t.nextToken();
lastName = t.nextToken();
}
...
在相应映射文件中无需映射该类的firstName和lastName属性而是映射name属性。它和相应数据表的NAME字段对应:<property name="name" column="NAME" />
<property>元素有一个access属性,如果将这个属性设置为field,则Hibernate可以运用java反射机制直接访问类的属性。例如如果设置<property name="name" access="field">,则Hibernate可以直接访问Customer.name属性,而不用调用setName()和getName()。
可以在setXXXX()中加入数据验证逻辑。不过更好的方法是在表示层或业务逻辑层进行验证。
<property>的formula属性,用来设置一个sql表达式,Hibernate将根据它来计算出派生属性的值。例如:
<property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)">,这里totalPrice的取值为与Customer对象关联的所有Order对象的price属性值的和。当Hibernate从数据库中查询Customer对象时,在select语句中会包含以上用于计算totalPrice派生属性的子查询语句。
可以控制insert和update语句,例如:
<property name="price" update="false" column="PRICE"/>
以上代码把<property>元素的update属性设为false,这表明在update语句中不会包含PRICE字段。同理可以设置<property>的insert属性等等.
<hibernate-mapping>可以设置default-schema属性,比如:
<hibernate-mapping default-schema="NE">
<class name="mypack.Customer" table="CUSTOMERS">
</hibernate-mapping>
以上代码对于映射文件中的Customer类,Hibernate会把它映射成为表NE_CUSTOMERS。
另外也可以为单独的类设定命名Schenma
<class name="mypack.Customer" table="CUSTOMERS" schema="NE">
同样可以得到上面的功能.
<hibernate-mapping>设置package属性时,比如:
<hibernate-mapping package="mypack">
<class name="Customer" table="CUSTOMERS" />
<class name="Order" table="ORDERS" />
</hibernate-mapping>
这样等同于:
<hibernate-mapping>
<class name="mypack.Customer" table="CUSTOMERS" />
<class name="mypack.Order" table="ORDERS" />
</hibernate-mapping>