??xml version="1.0" encoding="utf-8" standalone="yes"?>
struts
控制用的
hibernate
操作数据库的
spring
用解耦的
详细的说Q?/span>
STRUTS
?/span>
SSH
框架中v控制的作?/span>
,
其核心是
Controller,
?/span>
ActionServlet,
?/span>
ActionServlet
的核心就?/span>
Struts-confi g.xml.
主要控制逻辑关系的处?/span>
.
hibernate
是数据持久化?/span>
,
是一U新的对象、关pȝ映射工具
,
提供了从
Java
cd数据表的映射Q也提供了数据查询和恢复{机?/span>
,
大大减少数据讉K的复杂度。把Ҏ(gu)据库的直接操?/span>
,
转换为对持久对象的操?/span>
.
Struts
?/span>
spring
?/span>
Hibernate
在各层的作用
1
Q?/span>
struts
负责
web
?/span>
.
ActionFormBean
接收|页中表单提交的数据Q然后通过
Action
q行处理Q再
Forward
到对应的|页?/span>
?/span>
struts-config.xml
中定?/span>
<action-mapping>, ActionServlet
会加载?/span>
2
Q?/span>
spring
负责业务层管理,?/span>
Service
Q或
Manager).
1
Q?/span>
service
?/span>
action
提供l计的调用接口,装持久层的
DAO.
2
Q可以写一些自q业务Ҏ(gu)?/span>
3
Q统一?/span>
javabean
理Ҏ(gu)
4
Q声明式事务理
5.
集成
Hiberante
3
Q?/span>
Hiberante
Q负责持久化层,完成数据库的
crud
操作
hibernate
为持久层Q提?/span>
OR/Mapping
?/span>
它有一l?/span>
.hbm.xml
文g?/span>
POJO,
是跟数据库中的表相对应的。然后定?/span>
DAO
Q这些是跟数据库打交道的c,它们会?/span>
PO
?/span>
?/span>
struts+spring+hibernate
的系l中Q?/span>
对象的调用流E是Q?/span>
jsp-> Action
Q?/span>
> Service ->DAO ->Hibernate
?/span>
数据的流向是
ActionFormBean
接受用户的数据,
Action
数据从
ActionFromBean
中取出,装?/span>
VO
?/span>
PO,
再调用业务层?/span>
Bean
c,完成各种业务处理后再
forward
。而业务层
Bean
收到q个
PO
对象之后Q会调用
DAO
接口Ҏ(gu)Q进行持久化操作?/span>
Hibernate上手
一、Why HibernateQ?br /> 现在行“测试驱动开发”,怼的我觉得“目的驱动学?fn)”是一U比较好的接受新技术,新知识的途径。在学习(fn)一h的技术之前,首先得明到底有没有必要学习(fn)Q已有的技术是否已l工作的很好Q学?fn)这个新的技术是Z解决什么问题。如果你明确了以上问题,那么Lq学?fn)新的技术将会事半功倍,q且能快速应用到实际的开发当中来提高效益?br />要说HibernateQ就得先介绍一下Object/Relation MapperQORMQ,中文译为对象关pL。之所以会产生q样的概忉|源于目前软g开发中的一些不协调的思想。目前流行的~程模型是OOPQObject Oriented ProgrammingQ,面向对象的编E,而目前流行的数据库模型是Relational DatabaseQ这两者思考的方式不一Pq必然生了开发过E中的不协调。ORM框架Q也UCؓ持久层框ӞQ的出现是Z解决q样的问题,屏蔽底层数据库的操作Q以面向对象的方式提供给开发者操作数据库中数据的接口。目前流行的ORM框架有Apach OJBQHibernateQiBatis{等Q当然最完善Q最好用的是HibernateQ至我q样认ؓ。或怽对“持久层”感到迷惑,其实说白了很单,把数据放到数据库中叫做持久化Q内存种的数据当然不是持久的Q,那么负责q一操作的结构层面就叫做持久层。你以前应该听说q表现层Q业务层Q数据层Q那么持久层是在业务层和数据层之间的一层,或者说持久层是数据层的一部分?br />接下来,我想通过一个实际开发中的例子来说明ORM带给我们的好处。先来讲一下我们的需求,数据库中有三张表Q一张studentQ一张courseQ另外一张course_slection。其中student用来保存学生信息Qcourse用来表示评信息Qcourse_selection用来表示学生的选课信息。(表的详细l构q里我就省略了,因ؓqƈ不重要)现在要求~写一个程序,用来选出指定学号学生所选的评名字Q那么可能会出现以下几种E序~写的方式:
q段E序你一定看的很晕吧Q什么ؕ七八p的都搞在一P那么接下来看一D|q过的程序?br />2. 改进后的代码
q段代码的Ş式是一U被q泛采用的Ş式,相对W一D代码来_应该已经有所q步Q分M数据库连接操作,q把数据库连接信息交l单独的cd成(一般放在配|文仉面)Q往往在开发中q会引入数据库连接池QConnection PoolQ来提高性能Q我q里都尽量简化了。但q些q不能从Ҏ(gu)上改善程序的l构Q在业务代码中仍然杂了很多数据库操作,l构不清晰。下面来看一D彻底分L据库操作的代码:
是不是感觉代码少了很多?或许你对q段代码有点qhQ没关系Q后文会详细解释。我惛_解释一下DAO。其实DAO和Hibernate没有必然联系Q只不过一般用Hibernate的程序都用DAO模式。DAO的全U是Data Access ObjectQ程序要讉K数据库中的数据(包括获取Q更斎ͼ删除Q都通过DAO来访问,实际上DAO才是真正屏蔽了所有数据库操作的东西,q样在业务代码中可以完全隔L据层的代码。如果我告诉你,在真正用Hibernate开发的时候,要完成上文提到的功能Q需要手写的代码是“代码片D?”这么多Q甚x,你是不是有很大的动力d?fn)HibernateQ那么好吧,让我们开始Hibernate之旅?
q个cd是一个POJOQ你可以很明昄看出来它?yu)是一个JavaBean。我惌释它的courseSelection字段。很昄Q在数据库表student中,没有q个字段。这里的q个字段是因Z个外键引用,course_selection的student_id是一个外键,引用了student表中的id字段。那么在StudentcMcourseSelection来记录这L(fng)外键关系Q也是_当我们获取了Student对象以后Q就可以直接获取他的选课记录Q这样就Z层的调用提供了很大的方便。这里有Ҏ(gu)p没关系Q我在介l映定义文Ӟ*.hbm.xmlQ的时候还会提到这个问题?br />2. StudentDAO.java
q里的构造函数是用来启动HibernateQƈ获取session。打开一个sessionq当于打开了一个数据库q接Q然后我们就可以对这个sessionq行操作Q完成数据库操作Q完全不用写SQL语句。我q里Hibernate的启动方式写的很不规范,pȝ应该只需要完成一ơHibernate启动可以在不同的DAO中用,我把它写在构造函数里面纯_Ҏ(gu)Z化演CZ码?br />你可以看到save和deleteҎ(gu)都很单直接对对象操作Q而findById有些麻烦,因ؓq里有一个查询过E在里面。Hibernate里面查询可以用Criteriaq个cL完成Q我们也常用Hibernate独有的HQLQHibernate Query LanguageQ来完成查询。当然Hibernate也是支持原生SQL的。关于查询的详细信息请参考其他文章或书籍Q我只是演示一个流E,介绍一些概c?br />3. Student.hbm.xml
q个文g定义了StudentcdStudent表是如何映射的。class元素定义了SudentcdSTUDENT表映,然后定义了各个属性是如何映射的。如果一个属性是数据库的keyQ那么会用id标签来定义,column定义了当前类的属性和数据库中的哪个字D对应,generator是idҎ(gu)的。一般来说id是自增的Q由于我的数据库是用的OracleQ它没有自增字段Q要实现自增必须用SequenceQ这出了本文的范围Q所以我qassigned来简化示例代码。assigned表示id是用L(fng)定的?br />有一个比较特别的标签是setQ它对应着数据库中的外键关p,上文我提到的通过Student对象可以获得所有相关的选课记录是通过q里的定义实现的。name属性对应了StudentcM的字D名Qkey表示哪个字段是外键,one-to-many表示Student和CourseSelection是一对多关系Q这和事实相W。类似的q有many-to-oneQmany-to-manyQ不q这些都不常用,我不介绍了。HibernateҎ(gu)q个映射定义文gQ在实例化一个POJOQ比如StudentQ的时候,会自动的把定义过映射的属性用数据库中的数据填充,set也包括在内?br />4. hibernate.cfg.xml
q个文g我不解释了,自己看吧。结合上文StudentDAO的例子,我想你应该能看明白?br />看了q么多,或许你会有点头皮发麻QPOJOQDAOQ配|文?..好像要写的东西还是很多。值得庆幸的是现在Hibernate已经发展的比较成熟了Q有很多工具来帮助我们完成这些工作,比如MiddleGenQHibernate Synchronizer{等。我使用的开发工hEclipse+MyEclipseQ我所要做的只是把数据库表建好Q然后MyEclipse提供的工具会自动Ҏ(gu)数据库表生成POJOQDAOQ?.hbm.xmlQ甚至hibernate.cfg.xml都是自动完成的(前提是MyEclipse知道你的数据库连接信息)。我q不打算介绍如何用IDE来开发HibernateQ你可以参考IDE的帮助文档?br />到这里ؓ止,使用Hibernateq行开发的基本l成元素我都介绍好了Q强烈徏议你马上实践一遍,即有些不理解,也先依葫芦画瓢一个。对了,别忘了把Hibernate的包down下来攑ֈclasspath里面?/p> 三、Session与SessionFactory
我们通过Configuration来读取配|文Ӟ然后可以创建SessionFactoryQ这D代码在 所有系l中都大同小异,一般就是xml配置文g的名字不一P所以也没什么好说的?br />当我们有了SessionFactory以后可以获取Session了。调用SessionFactory.openSession()׃q回一个Session实例Q然后我们操作这个Session来访问数据库。值得一提的是Sessionq不是线E安全的Q也是每一个线E都必须有自qSession。所以我们一般通过以下Ҏ(gu)来获取和关闭SessionQ?br />代码片段9Q?/p>
可以看到Q我们通过threadLocal来保存每个线E的sessionQ这样就保证了各个线E之 间的互不q扰Q也保证了系l只有一个SessionFactory实例Q对于大多数应用来说已经 _了)。如果你使用MyEclipseq行开发的话,它会自动生成一个 ?HibernateSessionFactory.javaQ其中就包含了以上代码?br />好了Q现在我们已l获得了SessionQ下面我来介l以下Session的常用函敎ͼq些函数都有很多重蝲函数Q我只介l以下大概是q嘛的,不一一解释Q详l信息你可以查看Hibernate的API?br />1QSession.get()Q获取某个类的实例,一般都是通过id来获取比?br />Session.get(Student.class, "0361095"); 四、关键概늚理解 2Q?Object lifecycleQ对象生命周?br />在Hibernate中,对象分ؓ三种状态,TransientQ自q态)、PersistentQ持久状态)QDetachedQ游ȝ态)Q下面我分别解释一下?br />1、自q态:所谓自q态就是说q个对象是自qQ与Hibernate无关Q比 如: 2、持久状态:所谓持久状态就是指对象和数据库中的数据Q持久状态的数据Q ?有关联,也就是说对象被Hibernate所理了,比如Q?br />session.save(student); 3、游ȝ态:每次调用Session.close以后Q所有跟q个session有关的处?br />Persistant的对象就变成了游ȝ态。也怽要问Detached和Transient有什么区别。其实从我给的例子来说看不出什么区别,因ؓ我这里ID是给定的Q而真正开发的时候ID往往是自增的Q那么Transient的对象是没有ID 的,当save了以后就有了Q显而易见Detached的对象也是有IDQ只不过q个对象已经和Hibernateq了关pR但是游ȝ态的对象仍然和数据库 中的记录有一定联p,臛_游离状态的对象知道数据库中有条记录的ID为xxx。从q一点上来讲Q游ȝ态是可以自己创造出来的Q只要你知道数据库中的主键信息?br />在用Hibernate开发的时候要分清楚这三种状态,否则很容易出错。比如不能去save一个游ȝ态的对象Q不能去update一个自q态的对象{等?/p> 五、结束语 |