ORM思想(纯粹转载自己看)

        我们来研究一下为什么要从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的过渡。更多的细节是可以从官方文档和书籍中学到的,但我们应该更加看中它们设计思想的来源和闪光点,不是盲从它们的使用方法。

猜你喜欢

转载自1749599512.iteye.com/blog/2223850
今日推荐