笔者最近比较忙,一边在实习一边在寻找明年毕业更好的工作,不过论坛里的朋友非常支持小弟继续写,今天是周末,泡上一杯咖啡,继续与大家分享J2ee部分的学习经验。今天的主题是目前很流行也很好的一个开源框架-Spring。
引用《Spring2.0技术手册》上的一段话:
Spring的核心是个轻量级容器,它是实现IoC容器和非侵入性的框架,并提供AOP概念的实现方式;提供对持久层、事务的支持;提供MVC Web框架的实现,并对于一些常用的企业服务API提供一致的模型封装,是一个全方位的应用程序框架,除此之外,对于现存的各种框架,Spring也提供了与它们相整合的方案。
接下来笔者先谈谈自己的一些理解吧,Spring框架的发起者之前一本很著名的书名字大概是《J2ee Development without EJB》,他提倡用轻量级的组件代替重量级的EJB。笔者还没有看完那本著作,只阅读了部分章节。其中有一点分析觉得是很有道理的:
EJB里在服务器端有Web Container和EJB Container,从前的观点是各层之间应该在物理上隔离,Web Container处理视图功能、在EJB Container中处理业务逻辑功能、然后也是EBJ Container控制数据库持久化。这样的层次是很清晰,但是一个很严重的问题是Web Container和EJB Container毕竟是两个不同的容器,它们之间要通信就得用的是RMI机制和JNDI服务,同样都在服务端,却物理上隔离,而且每次业务请求都要远程调用,有没有必要呢?看来并非隔离都是好的。
再看看轻量级和重量级的区别,笔者看过很多种说法,觉得最有道理的是轻量级代表是POJO + IoC,重量级的代表是Container + Factory。(EJB2.0是典型的重量级组件的技术)我们尽量使用轻量级的Pojo很好理解,意义就在于兼容性和可适应性,移植不需要改变原来的代码。而Ioc与Factory比起来,Ioc的优点是更大的灵活性,通过配置可以控制很多注入的细节,而Factory模式,行为是相对比较封闭固定的,生产一个对象就必须接受它全部的特点,不管是否需要。其实轻量级和重量级都是相对的概念,使用资源更少、运行负载更小的自然就算轻量。
话题扯远了,因为Spring框架带来了太多可以探讨的地方。比如它的非侵入性:指的是它提供的框架实现可以让程序员编程却感觉不到框架的存在,这样所写的代码并没有和框架绑定在一起,可以随时抽离出来,这也是Spring设计的目标。Spring是唯一可以做到真正的针对接口编程,处处都是接口,不依赖绑定任何实现类。同时,Spring还设计了自己的事务管理、对象管理和Model2 的MVC框架,还封装了其他J2ee的服务在里面,在实现上基本都在使用依赖注入和AOP的思想。由此我们大概可以看到Spring是一个什么概念上的框架,代表了很多优秀思想,值得深入学习。笔者强调,学习并不是框架,而是框架代表的思想,就像我们当初学Struts一样……
1.Spring MVC
关于IoC和AOP笔者在上篇已经稍微解释过了,这里先通过Spring的MVC框架来给大家探讨一下Spring的特点吧。(毕竟大部分人已经很熟悉Struts了,对比一下吧)
众所周知MVC的核心是控制器。类似Struts中的ActionServlet,Spring里面前端控制器叫做DispatcherServlet。里面充当Action的组件叫做Controller,返回的视图层对象叫做ModelAndView,提交和返回都可能要经过过滤的组件叫做Interceptor。
让我们看看一个从请求到返回的流程吧:
(1) 前台Jsp或Html通过点击submit,将数据装入了request域
(2) 请求被Interceptor拦截下来,执行preHandler()方法出前置判断
(3) 请求到达DispathcerServlet
(4) DispathcerServlet通过Handler Mapping来决定每个reuqest应该转发给哪个后端控制器Controller
(5) 各式各样的后端控制器Controller来处理请求,调用业务层对象来处理业务逻辑,然后返回一个ModelAndView对象
(6) 当Controller执行完毕,Interceptor会调用postHandle来做后置处理
(7) ModelAndView代表了呈现画面是使用的Model数据对象和View对象,由于只能返回一个对象所有起了这个名字封装这两个对象。
(8) 由ViewResolver对象来解析每个返回的ModelAndView对象应该呈现到哪一个视图(Jsp/Html等)中(包括Exception Resolver)
(9) 当View绘制完成之后Interceptor又会跳出来执行它的afterCompletion方法做善后处理。当然Interceptor的行为完全是配置的而不是强制的。
这样一个完整的流程就这样结束了,个人感觉Spring的MVC框架稍显复杂,不像Struts-1那么容易上手。不管是Controller、Model、ViewRosovler、Handle Mapping还是View,Spring MVC框架都已经为你提供了多种实现,想最大程度的减少程序员的编码,增加框架的适用性。大家有兴趣可以继续深入研究哈!
2.Spring AOP
记得最初笔者请教他人Spring是一个什么东西的时候,每个人都会提到AOP这个词语。笔者在上一篇已经解释过AOP基本原理,这次来跟大家说说Spring的AOP编程吧。不同的AOP框架会有其对AOP概念不同的实现方式,主要的差别在于所提供的Pointcut、Aspects的丰富程度,以及它们如何被织入应用程序、代理的方式等等。先熟悉一下AOP中的几个重要概念:
(1) Cross-cutting:横切,说白了就是需要统一处理的集合
(2) Aspects:将散落各处的横切收集起来,设计成各个独立可重用的对象称为Aspects。
(3) Advice: 对横切的具体实现,即等待插入一段逻辑。
(4) Joinpoint:Advice插入流程的时机点。
(5) Pointcut: 用于选择Joinpoint的程序结构,可以通过Annotation或者XML实现。
(6) Weave: Advice被应用至对象之上的过程称之为织入,有编译期、类加载期、运行期三种时间点策略。
如果你采用实现接口的方式,Spring会在执行时期适用java的动态代理,如果不实现接口,Spring会使用CGLIB产生代理类。AOP的概念很大很泛,而Spring只使用了其中的部分特性,毕竟Spring的目标是轻量级框架,比如它只支持对Method的Joinpoint,而不支持对Field的Joinpoint,理由是为了封装性。
其实我们可以把概念看得简单一点,AOP的目的是减少冗余代码,增强对较大项目的全局监控。Spring利用AOP可以规定一个集合和一套规则,在这个集合里所有的方法被invoke即调用的时候,都必须按照那套规则走一遍。那么首先对其中10个方法都要用到的处理代码就只用写一遍,如果是这10个方法来了就织入这段代码;其次,按照规则,也许所有的牵扯某个模块的方法调用的时候,我都需要做日志或者进行验证,那么我只要立足于这个集合的入口和出口,管他从哪里来去哪里,都能被有效的监控。我监控的可能不止是某个方法单独的行为,我还可以加入对流程控制的监控规则。例如是论坛,我规定注册了才能登录,而登录后才能发帖回帖下资源,于是所有这类流程都会被收集到我眼皮地下通过。
PS:笔者最近忙于找工作的事,没有太多经历在论坛跟大家整理自己的笔记。最近也只是接触Spring的MVC比较多,对于Spring的其他特性,还没有更多的去实践,所以仅仅是泛泛而谈,只是介绍一个印象罢了。还是那句话,我们学习一个框架不是如何使用,而是它所带来的优秀的思想和理念,这比如何使用这个框架更有意义得多
Java杂谈(十一)--JVM
本来这次应该讲讲ORM的几个框架,但是笔者还没有完全总结出来,所以这里先插入一次学习JVM的心得。作为一个Java程序员,如果不了解JVM的工作原理,就很难从底层去把握Java语言和Java程序的运作机制。这里先推荐一个最权威的讲解JVM的文档,大家只要查过Java API的可以在里面的一个叫“API, Language, and Virtual Machine Document”的标题下看到四个子标题,第一个是我们最熟悉的Java API Specification,很少会有人注意到第三和第四个子标题,分别是“The Java Language Specification”和“The Java Machine Specification”后面都带有(Download)字样,JVM的那个URL直接链接到
http://java.sun.com/docs/books/vmspec/2nd-edition/这里地址。我们可以下载到一份非常权威详细的讲解JVM原理的官方文档。笔者业余时间花了1个星期来阅读,这里把自己的收获跟大家来分享一下,大概从这么几个方面来谈一谈:
1. JVM的实现机制
Java虚拟机就是一个小的计算机,有自己的指令集,有自己的文件系统,管理内部的表和数据,负责读取class文件里面字节码,然后转换成不同操作系统的CPU指令,从而使得Java程序在不同的操作系统上顺利的跑起来。所以Window的JVM能把字节码转换成Window系统的指令集,Linux的JVM能把字节码转换成Linux系统的字节,同理还有Solaris,它们彼此之间是不能通用的。最早一款的原型虽然是Sun公司开发的,但发展到现在其实任何厂商都可以自己去实现一个虚拟机,用来读取字节码转换成OS指令。甚至我们可以认为JVM跟Java编程语言都没有关系,因为你自己哪怕用记事本写一串字节码,也可以让JVM来解析运行,只要你的字节码能通过JVM的验证。
JVM的验证其实是很严格的,这里只讲一些有趣的地方。大家还记得Java的图标是一个杯咖啡麽?究其历史我们也许可以查出为什么,但还有更显而易见的方式是JVM怎么判断一个文件是否是class文件?JVM的做法是读取前4个字节转换成16进制数,判断是否等于0xCAFEBABE这个数。注意到这个单词了麽?“cafebabe”,代表着国外一种咖啡品牌,似乎叫做Peet’s coffee-baristas之类。创造Java的人为了方便记忆,选择了这样一个16进制数作为标准class文件的头,所以任何class文件都必须具有这4个字节的头部。我们可以用DataInput这个接口的实现类来验证一下,读取任何一个class文件的第一个int,int在Java里面是四个字节。转换成16进制一定会是0xcafebabe的。
所以这里想告诉大家的是,JVM其实并没有那么神秘,我们完全可以理解它的构造。
2. Java相关的基础概念
配合JVM的结构,在Java语言中也会有很多特点比较鲜明的地方。比如对数值计算从来不会检查位溢出。任何变量存储的二进制即使位全部为1了仍然可以加,全部为0了仍然可以减。大家只要稍微测试一下就知道了,看这几个例子:
int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;
max+1 == min; //true
min-1 == max; //true
0.0/0.0 //得到“NaN”(Not a number)
1/0.0 //Infinity
-1/0.0 //-Infinity
1或-1/0 //ArithmeticException唯一的异常情况
看完这几个例子,大家是否能更好的把握Java的数值运算呢?Java完全遵照IEEE-754的标准来定义单双精度浮点数以及其他的数值存储方式。
另外Java里面有一个概念叫做Daemon Thread(守护线程),知道它的存在主要是为了理解虚拟机的生命周期。当我们运行java命令,从main函数进入的那一刻起,虚拟机就开始启动运行了。Main所在的主线程也会启动起来,它属于非守护线程。与之同时一些守护线程也会同时启动,最典型的守护线程代表就是GC(垃圾收集器)线程。JVM虚拟机什么时候退出呢?是在所有的非守护线程结束的那一刻,JVM就exit。注意这个时候守护线程并未退出,很可能还要继续完成它的本职工作之后才会结束,但虚拟机的生命周期已经提前于它结束了。
3. JVM内部的基本概念
虚拟机内部还有一些概念,全部列举是不现实的,太繁琐也没有意义。除非您真的想自己去做一个JVM。笔者只列举部分概念:
首先我们来看一个叫做ReturnAddress的变量,它是JVM用来存储方法出口或者说进行跳转的依据,把任何地址存入这个变量就一定会按照这个地址来跳转。我们需要注意的就是finally有比方法return更高的赋值给ReturnAddress的优先级。同时存在方法return和finally return的话,一定是按照finally里面的return为准。
JVM有自己的Heap,能被所有线程共享,存储着所有的对象,内存是动态被分配的。对于每个线程,拥有自己的Stack,栈里面存储的单位叫做Frame(桢)。桢里面就记录着零时变量、对象引用地址、方法返回值等数据。JVM还有一个叫做Method Area的地方,存储着一段一段的可执行代码,每一段就是一个方法体,也能被所有线程共享。所以我们说一个线程其实从run方法跑起来,跟它的类中声明的其他方法是两个概念。因为其他的方法包括的所有的对象,这个时候都充当为资源被线程使用。
JVM有自己管理内存的方案,因为它具有文件系统的功能,我们可以看成一个小型的数据库,内部有许许多多不同的表。表的字段可能是另外一张表的地址,也可以直接就是一个存储数据值的地址值。JVM所有对运行时候类的解析验证计算等管理工作,实际上都是在管理这些表的变动,如果我们从数据库的角度来看,JVM所做的就是根据你的代码来操作那么多个表最后返回给你结果的过程。里面的表结构包括class的表、field表、method表、attribute表等。
4. JVM的指令集
JVM有自己的指令集,笔者从前也看过一些计算机组成结构和汇编语言的数,建议大家也稍微看看,了解设计一个高效可用的计算机指令集是多么复杂又多么重要的过程。对于JVM的指令集,职责是管理好Java程序编译出来的字节码,相对而言指令集的名称就多少和Java语言相关了,比如指令集里就有sastore,、saload表示array里面short的存和取、类似还有d2i表示从double转换成int、monitorenter表示进入synchronized块加锁、getstatic和putstatic表示对静态标量的存取、 jsr和ret等跳转指令……
为了便于记忆,设计JVM指令集的人们约定f开头的跟float有关,d跟double有关,i跟int有关,s跟short有关,a跟array有关。有兴趣的可以细读文档里面的每一个指令的作用。因为只是作为初步了解,这里就不多说了。
5. 一些Java关键字的实现原理
文档还很详细的列举了很多加载、初始化、加锁等操作的过程。笔者觉得比较有用的第一是记住Java里面只有Array不是由ClassLoader加载的对象,其他的对象全部都必须由一个ClassLoader来加载。另外package的概念除了类似于C++的namespace,是一种命名空间之外,底层的实现是规定同一个package下的类必须由同一个类加载器来加载,所以package的概念还可以认为是被同一个类加载器加载的类。
另外在多线程中,有很多细节值得去体会。每个线程有自己的Working memory,它们从能被共享的Main Memory中去读数据、修改、然后再存回去。笔者一直认为线程就是数据库里面事务的前身或者说祖先。我们只要稍微比较一下它们的行为,就会发现很多一致性。事务也是操作被事务共享的表数据,你改完我改,顺序不一致就会出现脏数据,而线程同样会出现脏数据。我们对线程加的锁策略,同样在事务中也有适用。当然多事务的情况显然比多线程更加复杂,但我们只要理解了多线程,相信对学习数据库事务的效果也是非常有帮助的。Java里面除了synchronized能够帮助同步多线程之外,还有一个弱同步的操作关键字是volatile,它产生在变量上的约束在文档中也有详细的说明。因为很复杂,考虑到篇幅笔者就不打算解释一遍了。
好了,又是新的一篇结束了。大概再有一两篇笔者大学关于Java所学就差不多说完了。不足之处大家尽管提出来,笔者愿意接受各种职责批评,因为笔者认为失败的教训往往比成功更加助人成长。这个帖子一直以来得到那么多朋友的大力支持和鼓励,笔者在这里真诚的说一声谢谢!因为笔者即将毕业投入茫茫人海去从草根阶层开始挣扎,最近冷静的想了很多,即使毕业了,要提高的不止是技术,还包括很多综合素质,也许并不能马上找到如意的团队和工作岗位,只能承认自己是弱势群体,有时不得不向现实的生活低头,不知道今后是否还有这闲心去写学习笔记,去坚持走分享的道路。其实很多人我认为也很有心去分享,但被现实的生活束缚了手脚。所以也期望还呆在学校里的大学生们好好努力的珍惜那份无忧虑的心境和安静的环境,好好充实自己吧!
Java杂谈(十二)——ORM
这是最后一篇Java杂谈了,以ORM框架的谈论收尾,也算是把J2ee的最后一方面给涵盖到了,之所以这么晚才总结出ORM这方面,一是笔者这两周比较忙,另一方面也想善始善终,仔细的先自己好好研究一下ORM框架技术,不想草率的敷衍了事。
其实J2ee的规范指南里面就已经包括了一些对象持久化技术,例如JDO(Java Data Object)就是Java对象持久化的新规范,一个用于存取某种数据仓库中的对象的标准化API,提供了透明的对象存储,对开发人员来说,存储数据对象完全不需要额外的代码(如JDBC API的使用)。这些繁琐的工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO很灵活,因为它可以在任何数据底层上运行。JDBC只是面向关系数据库(RDBMS)JDO更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML以及对象数据库(ODBMS)等等,使得应用可移植性更强。我们如果要理解对象持久化技术,首先要问自己一个问题:为什么传统的JDBC来持久化不再能满足大家的需求了呢?
笔者认为最好是能用JDBC真正编写过程序了才能真正体会ORM的好处,同样的道理,真正拿Servlet/Jsp做过项目了才能体会到Struts、Spring等框架的方便之处。很幸运的是笔者这两者都曾经经历过,用混乱的内嵌Java代码的Jsp加Servlet转发写过完整的Web项目,也用JDBC搭建过一个完整C/S项目的后台。所以现在接触到新框架才更能体会它们思想和实现的优越之处,回顾从前的代码,真是丑陋不堪啊。^_^
回到正题,我们来研究一下为什么要从JDBC发展到ORM。简单来说,传统的JDBC要花大量的重复代码在初始化数据库连接上,每次增删改查都要获得Connection对象,初始化Statement,执行得到ResultSet再封装成自己的List或者Object,这样造成了在每个数据访问方法中都含有大量冗余重复的代码,考虑到安全性的话,还要加上大量的事务控制和log记录。虽然我们学习了设计模式之后,可以自己定义Factory来帮助减少一部分重复的代码,但是仍然无法避免冗余的问题。其次,随着OO思想深入人心,连典型的过程化语言Perl等都冠冕堂皇的加上了OO的外壳,何况是Java中繁杂的数据库访问持久化技术呢?强调面向对象编程的结果就是找到一个桥梁,使得关系型数据库存储的数据能准确的映射到Java的对象上,然后针对Java对象来设计对象和方法,如果我们把数据库的Table当作Class,Record当作Instance的话,就可以完全用面向对象的思想来编写数据层的代码。于是乎,Object Relationship Mapping的概念开始普遍受到重视,尽管很早很早就已经有人提出来了。
缺点我们已经大概清楚了,那么如何改进呢?对症下药,首先我们要解决的是如何从Data Schema准备完美的映射到Object Schema,另外要提供对数据库连接对象生命周期的管理,对事务不同粒度的控制和考虑到扩展性后提供对XML、Properties等可配置化的文件的支持。到目前为止,有很多框架和技术在尝试着这样做。例如似乎是封装管理得过了头的EJB、很早就出现目前已经不在开发和升级了的Apache OJB、首先支持Manual SQL的iBATIS,还有公认非常优秀的Hibernate等等。在分别介绍它们之前,我还想反复强调这些框架都在试图做什么:
毕竟Java Object和数据库的每一条Record还是有很大的区别,就是类型上来说,DB是没有Boolean类型的。而Java也不得不用封装类(Integer、Double等)为了能映射上数据库中为null的情况,毕竟Primitive类型是没有null值的。还有一个比较明显的问题是,数据库有主键和外键,而Java中仍然只能通过基本类型来对应字段值而已,无法规定Unique等特征,更别提外键约束、事务控制和级联操作了。另外,通过Java Object预设某Field值去取数据库记录,是否在这样的记录也是不能保证的。真的要设计到完全映射的话,Java的Static被所有对象共享的变量怎么办?在数据库中如何表现出来……
我们能看到大量的问题像一座座大山横在那些框架设计者们面前,他们并不是没有解决办法,而是从不同的角度去考虑,会得到很多不同的解决方案,问题是应该采取哪一种呢?甚至只有等到真正设计出来了投入生产使用了,才能印证出当初的设想是否真的能为项目开发带来更多的益处。笔者引用一份文档中提到一个健壮的持久化框架应该具有的特点:
A robust persistence layer should support----
1. Several types of persistence mechanism
2. Full encapsulation of the persistence mechanism.
3. Multi-object actions
4. Transactions Control
5. Extensibility
6. Object identifiers
7. Cursors: logical connection to the persistence mechanism
8. Proxies: commonly used when the results of a query are to be displayed in a list
9. Records: avoid the overhead of converting database records to objects and then back to records
10. Multi architecture
11. Various database version and/or vendors
12. Multiple connections
13. Native and non-native drivers
14. Structured query language queries(SQL)
现在来简短的介绍一下笔者用过的一些持久化框架和技术,之所以前面强调那么多共通的知识,是希望大家不要盲从流行框架,一定要把握它的本质和卓越的思想好在哪里。
1. Apache OJB
OJB代表Apache Object Relational Bridge,是Apache开发的一个数据库持久型框架。它是基于J2ee规范指南下的持久型框架技术而设计开发的,例如实现了ODMG 3.0规范的API,实现了JDO规范的API, 核心实现是Persistence Broker API。OJB使用XML文件来实现映射并动态的在Metadata layer听过一个Meta-Object-Protocol(MOP)来改变底层数据的行为。更高级的特点包括对象缓存机制、锁管理机制、Virtual 代理、事务隔离性级别等等。举个OJB Mapping的简单例子ojb-repository.xml:
<class-descriptor class=”com.ant.Employee” table=”EMPLOYEE”>
<field-descriptor name=”id” column=”ID”
jdbc-type=”INTEGER” primarykey=”true” autoincrement=”true”/>
<field-descriptor name=”name” column=”NAME” jdbc-type=”VARCHAR”/>
</class-descrptor>
<class-descriptor class=”com.ant.Executive” table=”EXECUTIVE”>
<field-descriptor name=”id” column=”ID”
jdbc-type=”INTEGER” primarykey=”true” autoincrement=”true”/>
<field-descriptor name=”department” column=”DEPARTMENT” jdbc-type=”VARCHAR”/>
<reference-descriptor name=”super” class-ref=”com.ant.Employee”>
<foreignkey field-ref=”id”/>
</reference-descriptor>
</class-descrptor>
2. iBATIS
iBATIS最大的特点就是允许用户自己定义SQL来组配Bean的属性。因为它的SQL语句是直接写入XML文件中去的,所以可以最大程度上利用到SQL语法本身能控制的全部特性,同时也能允许你使用特定数据库服务器的额外特性,并不局限于类似SQL92这样的标准,它最大的缺点是不支持枚举类型的持久化,即把枚举类型的几个对象属性拼成与数据库一个字段例如VARCHAR对应的行为。这里也举一个Mapping文件的例子sqlMap.xml:
<sqlMap>
<typeAlias type=”com.ant.Test” alias=”test”/>
<resultMap class=”test” id=”result”>
<result property=”testId” column=”TestId”/>
<result property=”name” column=”Name”/>
<result property=”date” column=”Date”/>
</resultMap>
<select id=”getTestById” resultMap=”result” parameterClass=”int”>
select * from Test where TestId=#value#
</select>
<update id=”updateTest” parameterClass=”test”>
Update Tests set Name=#name#, Date=”date” where TestId=#testId#
</update>
</sqlMap>
3. Hibernate
Hibernate无疑是应用最广泛最受欢迎的持久型框架,它生成的SQL语句是非常优秀。虽然一度因为不能支持手工SQL而性能受到局限,但随着新一代Hibernate 3.x推出,很多缺点都被改进,Hibernate也因此变得更加通用而时尚。同样先看一个Mapping文件的例子customer.hbm.xml来有一个大概印象:
<hibernate-mapping>
<class name=”com.ant.Customer” table=”Customers”>
<id name=”customerId” column=”CustomerId” type=”int” unsaved-value=”0”>
<generator class=”sequence”>
<param name=”sequence”> Customers_CustomerId_Seq </param>
</generator>
</id>
<property name=”firstName” column=”FirstName”/>
<property name=”lastName” column=”LastName”/>
<set name=”addresses” outer-join=”true”>
<key column=”Customer”/>
<one-to-many class=”com.ant.Address”/>
</set>
…
</class>
</hibernate-mapping>
Hibernate有很多显著的特性,最突出的就是它有自己的查询语言叫做HQL,在HQL中select from的不是Table而是类名,一方面更加面向对象,另外一方面通过在hibernate.cfg.xml中配置Dialect为HQL可以使得整个后台与数据库脱离耦合,因为不管用那种数据库我都是基于HQL来查询,Hibernate框架负责帮我最终转换成特定数据库里的SQL语句。另外Hibernate在Object-Caching这方面也做得相当出色,它同时管理两个级别的缓存,当数据被第一次取出后,真正使用的时候对象被放在一级缓存管理,这个时候任何改动都会影响到数据库;而空闲时候会把对象放在二级缓存管理,虽然这个时候与数据库字段能对应上但未绑定在一起,改动不会影响到数据库的记录,主要目的是为了在重复读取的时候更快的拿到数据而不用再次请求连接对象。其实关于这种缓存的设计建议大家研究一下Oracle的存储机制(原理是相通的),Oracle牺牲了空间换来时间依赖于很健壮的缓存算法来保证最优的企业级数据库访问速率。
以上是一些Mapping的例子,真正在Java代码中使用多半是继承各个框架中默认的Dao实现类,然后可以通过Id来查找对象,或者通过Example来查找,更流行的是更具Criteria查找对象。Criteria是完全封装了SQL条件查询语法的一个工具类,任何一个查询条件都可以在Criteria中找到方法与之对应,这样可以在Java代码级别实现SQL的完全控制。另外,现在许多ORM框架的最新版本随着JDk 5.0加入Annotation特性都开始支持用XDoclet来自动根据Annotation来生成XML配置文件了。
笔者不可能详细的讲解每一个框架,也许更多的人在用Hibernate,笔者是从OJB开始接触ORM技术的,它很原始却更容易让人理解从JDBC到ORM的过渡。更多的细节是可以从官方文档和书籍中学到的,但我们应该更加看中它们设计思想的来源和闪光点,不是盲从它们的使用方法。
到这里全部Java杂谈这个主题就正式结束了,笔者也可以长叹一口气,拿到毕设题目后也该开始忙自己的毕业设计了。最近看了很多Spring AOP的资料,实习下班回家还会研究Ajax和极限编程,如果有时间了话,会把自己的学习笔记拿出来分享的。衷心希望大家都能不断的进步,在喜欢的道路上不回头的走下去……^_^