第1章 ORM框架概述Word格式.docx
- 文档编号:21951218
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:12
- 大小:186.58KB
第1章 ORM框架概述Word格式.docx
《第1章 ORM框架概述Word格式.docx》由会员分享,可在线阅读,更多相关《第1章 ORM框架概述Word格式.docx(12页珍藏版)》请在冰豆网上搜索。
大家都知道,目前比较流行的数据库有:
Oracle、MySQL、SQLServer、DB2….。
持久化对象就是指已经存储到数据库或磁盘中的数据。
为了保证一个对象持久存储,必须将其状态保存到非易失性的存储设备中持久化对象可以在创建它的程序的作用域之外保持其自身的状态。
不同的对象有不同的状态,状态数据都存放在对象的实例变量中。
位于内存的堆栈空间中的对象在计算机关机或断电后会丢失,所以,我们为了永久的保存这些对象的状态,并需要的时候能够再获得这个对象数据,就需要对它们进行持久化操作。
在Java中,我们通常采用以下三种方式对对象进行持久化:
Ø
序列化对象,将对象进行序列化,以二进制格式存入文本文件。
将对象持久化到XML文件中。
将对象持久化到数据库中,目前,采用最多的就是关系型数据库。
大家都知道,关系型数据库中遵循了一条重要原则就是”数据独立性”,即数据可以独立于应用程序而存在。
因此,数据可以比任何应用程序都存在得更久。
同时,它的性能及安全性也有保障。
并且,不同的应用程序之间还可以共享这些数据。
前面两种方式,我们在JavaSE基础课程上都已经进行了学习,本书的重点是要学习第三种方式,把应用程序中的数据持久到到数据库中去。
1.1.2分层体系结构和持久层
随着应用软件的不断发展,应用程序从简单变得越来越庞大,功能越来越多,业务也更加的复杂。
通过程序员的不停的总结,分层也成为了计算机软件设计中的一种重要思想。
从单层结构发展到双层结构,双层结构分为应用层与数据库访问层,见图1.1。
在双层结构中,用户界面和业务逻辑控制都由应用层负责实现,数据库访问层(持久层)负责与数据库进行交互。
这样导致用户界面代码和业务逻辑代码混合在一起,产生了程序结构不清晰、维护困难等问题。
同时,不懂编程的美工开发人员也无法参与到软件开发过程中。
再后来,我们把应用层再次进行细分,将用户界面的设计从业务逻辑中进行分离,形成单独的一层——表示层,演变成三层结构。
经典的软件应用体系三层结构有三层:
表示层、业务逻辑层、数据访问层(持久层),见图1.2所示。
图1.1图1.2
各层主要功能如下:
表示层:
提供了与用户进行交互的界面,作用是展示数据和收集数据。
业务逻辑层:
完成业务逻辑处理,处理表示层提交的数据请求,并将要保存的数据提交给下层数据访问层。
或根据表示的请求向底层数据访问层请求数据。
数据访问层(持久层):
存储需要持久化的数据。
数据库独立于应用程序,它只是提供了一种持久化的表现形式。
在上面的三层结构中,持久层对数据访问逻辑进行抽象,业务逻辑层通过持久层提供的数据访问接口来访问底层数据库中的数据。
这不仅将应用开发人员从底层操作中解放出来,更多的去关注业务处理,同时,由于业务逻辑与数据访问分离开来,使得开发人员分工更加细化。
某些数据库比较精通的开发人员可以专门负责持久层的数据库访问操作,而对业务流程比较熟悉的开发人员可以避开繁琐的数据库访问细节,只实现业务逻辑。
这样,才更加有利于团队合作开发,有利于软件的健壮性,可维护性。
1.1.3持久层实现
持久层的实现是和数据库紧密相连的,在Java领域中,访问数据库的技术通常都采用JDBC,至于JDBC,我们在前面的课程中已经进行了学习,这里不做详述。
JDBC使用灵活而且访问速度快,性能好,但是JDBC不仅要操作对象,还需要操作关系,并不是完全面向对象编程,同时,开发人员还要编写大量的重复的数据库操作代码。
近年来涌现出许多新的持久层框架,这些框架为持久层的实现提供了更多的选择,同时,也简化了繁琐、重复的代码。
目前,比较流行的持久层框架包括:
Hibernate、iBatis、MyBites、JDO、Nhibernate、LinqToSQL….。
1.2对象关系映射
面向对象的开发方式是现今企业级应用开发中的主流开发方法,关系型数据库是企业级应用环境中永久存放数据的主要方式。
在软件开发过程中,对象和关系数据是业务实体的两种不现的表现形式,业务实体在内存中的存在形式为对象,要想将业务实体永久存储则只能将其放入关系型数据库中,在数据库中它以关系型数据的形式存在。
由面向对象基本理论知道,内存中的对象之间是存在着关联和继承关系的,而在关系型数据库中,数据之间无法直接表达多对多的关联和继承关系。
此时,对象—关系映射组件就应运而生了。
对象关系映射(英语:
ObjectRelationMapping,简称ORM,或O/RM,或O/Rmapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
从效果上说,它其实是创建了一个可在编程语言里使用的—“虚拟对象数据库”。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。
为了解决这个不匹配的现象,对象关系映射技术应运而生。
对象关系映射提供了概念性的、易于理解的模型化数据的方法。
ORM方法论基于三个核心原则:
简单:
以最基本的形式建模数据。
传达性:
数据库结构被任何人都能理解的语言文档化。
精确性:
基于数据模型创建正确标准化的结构。
典型地建模者通过收集来自那些熟悉应用程序但不熟练的数据建模者的人的信息开发信息模型。
建模者必须能够用非技术企业专家可以理解的术语在概念层次上与数据结构进行通讯。
建模者也必须能以简单的单元分析信息,对样本数据进行处理。
ORM专门被设计为改进这种联系。
回想以前开发一个应用程序的时候(不使用ORM),我们写了不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。
并且在DDL中也写了很多的方法来读取对象数据,改变状态对象等等任务。
而这些代码写起来总是重复的。
如果打开你最近的程序,看看DAL代码,你肯定会看到很多近似的通用的模式。
我们以保存对象的方法为例,你传入一个对象,为Statement对象添加Parameter,把所有属性和对象对应,获取Conncation对象,然后Statement执行操作方法。
对于每个对象都要重复的写这些代码。
除此之外,还有更好的办法吗?
有,引入一个ORM。
实质上,一个ORM会为你生成DAL。
与其自己写DAL代码,不如用ORM。
你用ORM实现数据的增、删、改、查,ORM负责生成SQL,你只需要关心对象就好。
简单的说:
ORM相当于中继数据。
具体到产品上,例如Hibernate、EntityFramework、MyBites、Nhibernate。
DLINQ中实体类的属性[Table]就算是一种中继数据。
一般的ORM包括以下四部分:
一个对持久类对象进行CRUD操作的API;
一个语言或API用来规定与类和类属性相关的查询;
一个规定MappingMetaData的工具;
一种技术可以让ORM的实现同事务对象一起进行DIRTYCHECKING,LAZYASSOCIATIONFETCHING以及其他的优化操作。
ORM把应用程序世界表示为具有角色(关系中的部分)的一组对象(实体或值)。
ORM有时也称为基于事实的建模,因为它把相关数据描述为基本事实。
这些事实如果分割为再小的事实就会丢失信息。
例如:
人有电话
人住在某个地方
人生于某个日期
人在某个日期被雇佣
ORM提供的不只是描述不同对象间关系的一个简单而直接的方式。
ORM还提供了灵活性。
使用ORM创建的模型比使用其它方法创建的模型更有能力适应系统的变化。
另外,ORM允许非技术企业专家按样本数据谈论模型,因此他们可以使用真实世界的数据验证模型。
因为ORM允许重用对象,数据模型能自动映射到正确标准化的数据库结构。
ORM模型的简单性简化了数据库查询过程。
使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。
本质上,ORM完成的是将数据从一种表现形式转换为另一种表现形式。
因此,对象—关系映射系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的关系映射。
Hibernate就是一种实现了ORM的框架。
如下图1.3所示。
图1.3
1.3实体对象生命周期
大家都知道,在Java编程过程中,一个对象通过new关键字创建后,这个对象就会驻扎在内存区域之中,一直要到应用程序结束或设置对象为NULL,此对象才会被回收机制进行回收。
那么,在Hibernate中,我们所操作的实体对象的生命周期又是什么样子的呢?
其实,实体对象的生命周期在Hibernate应用中是一个很关键的概念,正确的理解实体对象的生命周期将对我们应用Hibernate做持久层设计起到很大的作用。
而所谓的实体对象的生命周期就是指实体对象由产生到被垃圾回收机制回收的一段过程,在这过程中我们需要理解的就是实体对象生命周期中的三种状态。
1.3.1自由状态(Transient)
也叫瞬时状态,所谓的瞬时状态是指对象被创建,自由的存储在内存之中,与数据库中的记录无关,也没有被纳入Hibernate的实体管理容器之中。
特征:
∙与数据库中的记录没有任何关系,即没有与其相关联的数据库记录。
∙与session没有任何关系.即没有通过session对象的实例对其进行任何持久化的操作。
1.3.2持久状态(Persistent)
所谓的持久状态是指实体对象已经处于被Hibernate实体管理容器所管理的状态,这种状态下这个实体对象的引用将被纳入Hibernate实体管理容器容器所管理,处于Persistent状态的实体对象,对它的变更也将被固化到数据库中。
处于持久状态的实体可以简单的理解为:
如果一个实体对象与session发生了关联,并且处于session的有效期内,那么这个实体对象就处于Persistent状态。
∙每个persistent状态的实体对象都与一个session对象的实例相关联
∙处于Persistent状态的实体对象是与数据库中的记录相关联的.
∙Hibernate会依据persistent状态的实体对象的属性变化而改变数据库中相对应的记录.
1.3.3.游离状态
所谓游离状态,就是指处于持久状态的实体对象,其对应的session关闭以后,那么这个实体就处于游离状态。
我们可以认为session对象就是一个持久状态的宿主,一旦这个宿主失效,那么这个实体就处于游离状态。
∙游离态是由持久态实体对象转变而来的。
∙游离态实体不再与session对象相关联。
∙游离态实体对象与数据库中的记录没有直接联系,对其所做的任何修改将不会影响到到数据库中的数据。
∙游离态实体对象在数据库有相对应的数据记录,如果没有被其他事务删除。
这里要注意的是,既然瞬时状态的实体与游离状态的实体都与Hibernate的实体管理容器没有关系,那他们到底存在哪些差异?
差异就在于处于瞬时状态的对象只有一个Name的属性,此时的test对象所包含的数据信息仅限于此,它与数据库中的记录没有任何瓜葛,但是处于游离状态的实体已经不止包含Name这个属性了,它还被赋予了主键也就是通常POJO里的id属性,由于id是主键,它可以确定数据库表中的唯一的一条记录,那么自然的处于游离状态的实体就能与数据库表中拥有相同id的记录相关联。
这就是他们之间所存在的差异。
简而言之,瞬时状态的实体缺乏与数据库表记录之间的联系,而游离状态的试题恰恰相反,只不过是脱离了session这个数据库操作平台而已。
1.4无接口代理模式实现及ASM/CGLIB库简介
1.4.1ASM简介。
ASM是一个Java字节码操控框架。
它可以动态生成类或增强现有类的功能。
ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为。
Javaclass被存储在严格格式定义的.class字节码文件中,这些类文件拥有足够的元数据来解析类中的所有元素:
类名称、方法、属性以及Java字节码(指令)。
ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
ASM提供了更为现代的编程模型。
对于ASM来说,Javaclass被描述为一棵树;
使用“Visitor”模式(观察者模式)来遍历整个二进制结构;
事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解Java类文件格式的所有细节:
ASM框架提供了默认的“responsetaker”处理这一切。
1.4.2如何使用ASM
使用ASM框架需要导入asm的相关jar包,这些包可以去他的官网下载,官网下载地址是:
http:
//asm.ow2.org/download/index.html。
框架中的核心类有以下几个:
ClassReader:
该类用来解析编译过的class字节码文件。
ClassWriter:
该类用来重新构建编译后的类,比如说修改类名、属性以及方法,甚至可以生成新的类的字节码文件。
ClassAdapter:
该类也实现了ClassVisitor接口,它将对它的方法调用委托给另一个ClassVisitor对象。
1.4.3ASM字节码处理框架
ASM字节码处理框架是用Java开发的,而且使用基于观察者模式生成字节码,以及驱动类到字节码的转换,通俗的讲,它就是对class文件的CRUD,经过CRUD后的字节码可以转换为类。
ASM的解析方式类似于SAX解析XML文件,它综合运用了观察者模式、职责链模式、桥接模式等多种设计模式,相对于其他类似工具如BCEL、SERP、Javassist等等。
CGLIB它的最大的优势就在于其性能更高,其jar包仅30K。
Hibernate和Spring都使用了CGLIB代理,而CGLIB本身就是使用的ASM,可见ASM在各种开源框架都有广泛的应用。
ASM是一个强大的框架,利用它我们可以做到:
获得class文件的详细信息,包括类名、父类名、接口、成员名、方法名、方法参数名、局部变量名、元数据等。
对class文件进行动态修改,如增加、删除、修改类方法、在某个方法中添加指令等等。
1.4.4什么是CGLIB(动态代理)
CGLIB(CodeGenerationLibrary)是一个强大的,高性能,高质量的Code生成类库。
它可以在运行期扩展Java类与实现Java接口,是对ASM的封装,简化了ASM的操作,降低了ASM的使用门槛,实现了在运行期动态生成新的class。
CGLIB被许多AOP的框架使用,Hibernate的懒加载使用到了ASM,Spring的AOP也使用到了ASM。
当你建立一个Hibernate映射对象并使用懒加载配置时,在内存中生成的对象就不再是你实现的那个类了,而是Hibernate根据字节码技术为你的类为模板构造的一个新类。
在Spring中,类名的输出可能是:
proxy$xxx,在Hibernate中,输出的类名可能是:
<
类名>
$xxx$xxx这样子的名字。
CGLIB包的基本代码很少,但学起来有一定的困难,主要是缺少文档,API描述过于简单,这也是开源软件的一个不足之处。
目前CGLIB的版本是cglib-3.1.jar,资源下载地址:
net.sf.cglib.core:
底层字节码处理类,他们大部分与ASM有关系。
net.sf.cglib.transform:
编译期或运行期类和类文件的转换。
net.sf.cglib.proxy:
实现创建代理和方法拦截器的类。
net.sf.cglib.reflect:
实现快速反射和C#风格代理的类。
net.sf.cglib.util:
集合排序工具类。
net.sf.cglib.beans:
JavaBean相关的工具类。
CGLIB包是在ASM之上的一个高级别的层。
对代理那些没有实现接口的类非常有用。
本质上,它是通过动态的生成一个子类去覆盖所要代理类的不是final的方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(interceptors),这比JDK动态代理方法快多了。
可见,CGLIB的原理是对指定的目标类动态生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类和final方法进行代理。
1.4.5用CGLIB实现动态代理
创建一个具体类的代理时,通常要用到的CGLIB包的APIs:
net.sf.cglib.proxy.Callback接口:
在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。
net.sf.cglib.proxy.MethodInterceptor接口:
是最通用的回调(callback)类型,它经常被AOP用来实现拦截(intercept)方法的调用。
这个接口只定义了一个方法。
当net.sf.cglib.proxy.MethodInterceptor做为所有代理方法的回调时,当对基于代理的方法调用时,在调用原对象的方法的之前会调用这个方法,如图1.4所示。
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。
原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用net.sf.cglib.proxy.MethodProxy对象调用。
net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。
在这个方法中,我们可以在调用原方法之前或之后注入自己的代码。
图1.4
net.sf.cglib.proxy.MethodInterceptor能够满足任何的拦截(interception)需要,当对有些情况下可能过度。
为了简化和提高性能,CGLIB包提供了一些专门的回调(callback)类型。
net.sf.cglib.proxy.FixedValue:
为提高性能,FixedValue回调对强制某一特别方法返回固定值是有用的。
net.sf.cglib.proxy.NoOp:
NoOp回调把对方法调用直接委派到这个方法在父类中的实现。
net.sf.cglib.proxy.LazyLoader:
当实际的对象需要延迟装载时,可以使用LazyLoader回调。
一旦实际对象被装载,它将被每一个调用代理对象的方法使用。
net.sf.cglib.proxy.Dispatcher:
Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用。
net.sf.cglib.proxy.ProxyRefDispatcher:
ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递。
代理类的所以方法经常会用到回调,当然你也可以使net.sf.cglib.proxy.CallbackFilter有选择的对一些方法使用回调,这种考虑周详的控制特性在JDK的动态代理中是没有的。
在JDK代理中,对java.lang.reflect.InvocationHandler方法的调用对代理类的所有方法都有效。
CGLIB的代理包也对net.sf.cglib.proxy.Mixin提供支持。
基本上,它允许多个对象被绑定到一个单一的大对象。
在代理中对方法的调用委托到下面相应的对象中。
接下来我们使用CGLIB来实现无接口代理模式实现在类的方法调用前后向控制台输出两句字符串。
1、定义一个HelloWorld类,没有实现接口
当在调用sayHello方法时,通过MethodInterceptor接口中的intercept()回调方法,在sayHello方法前后各加入一句法。
2、创建一个代理类:
CglibProxy,需要实现MethodInterceptor接口,并需要导入相关的jar包:
为了更好的使用代理,我们可以使用自己定义的MethodInterceptor类型回调来代替net.sf.cglib.proxy.NoOp回调。
当对代理中所有方法的调用时,都会转向MethodInterceptor类型的拦截(intercept)方法,在拦截方法中再调用底层对象相应的方法。
3、最后,我们来实现代理测试类。
4、最后,我们看看测试结果。
5、基本流程:
需要自己写代理类,它实现MethodInterceptor接口,有一个intercept()回调方法用于拦截对目标方法的调用,里面使用methodProxy来调用目标方法。
创建代理对象要用Enhance类,用它设置好代理的目标类、有intercept()回调的代理类实例、最后用create()创建并返回代理实例。
【本章总结】
本章学习了什么是数据持久化操作,这也是软件开发中非常重要一个环节,然后概述了ORM,对象关系映射,可以通过ORM映射关系,把数据库中的数据转化为项目程序中的实体对象,再介绍了实体对象的生命周期,在项目程序中,实体对象的有三种状态:
瞬时状态、持久状态、游离状态。
最后简述了Java程序中ASM/CGLIB的动态代理,在程序运行中可以创建类的代理对象,运行ASM直接产生二进制class文件,在类被加载入Java虚拟机之前动态去改变
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第1章 ORM框架概述 ORM 框架 概述