持久化和ORM 以及hibernate 的ORM 实现
按通常的系统设计,使用 JDBC 操作数据库,业务处理逻辑和数据存取逻辑是混杂在一起的。?
一般基本都是如下几个步骤:?1、建立数据库连接,获得 Connection 对象。?2、根据用户的输入组装查询 SQL 语句。?3、根据 SQL 语句建立 Statement 对象 或者 PreparedStatement对象。?4、用 Connection 对象执行 SQL语句,获得结果集 ResultSet对象。?5、然后一条一条读取结果集 ResultSet 对象中的数据。?6、根据读取到的数据,按特定的业务逻辑进行计算。?7、根据计算得到的结果再组装更新 SQL 语句。?8、再使用 Connection 对象执行更新 SQL语句,以更新数据库中的数据。?9、最后依次关闭各个 Statement 对象和 Connection对象。?而且取出的数据是一次性的,取出后马上用,用后就消失,它的存在是"瞬间"的.但在程序中,我们经常希望我们的数据能长时间存在内存中,因为我们可能需要在多个地方用到.所以我们经常会用session保存,或其他手段.但太依赖内存会有很严重的后果,一是内存空间有限,内存价格高,而且内存会面临断电等情况,断电后内存中的所有消失都将不复存在.这时候,我们就希望我们的数据能够"持久"的存在.持久化的实现有很多种,如:放将内容放在本地文件中,将内容放在数据库中等;
这里有另一个概念:序列化--它是指将对象变为数据流,或将数据流变为对象.它主要是用于对象的传输中;?
有了持久化的需求后,我们就要考虑如何来实现,用哪种方式实现,我们知道数据库的结构和对象的结构非常相似,对象有属性(或者叫字段),表也有字段,而且字段都有值,类型.所以我们就希望能够通过手段将对象的值和数据库表的值对应起来.这种对应就叫:ORM:ObjectRole Modeling对象映射模型;这种模型也让开发人员将数据库的操作也能看作是<面向对象>的了.?
在上面的传统的JDBC操作流程中,我们可以将从数据库取出来的数据用自己本地的JAVA对象进行封装,即:新建对应的类,然后将值赋给对象.因为对象就能在内存中保存,所以就打破了数据值瞬间的瓶颈.在数据存储时,我们先对对象的各属性进行设置.在最后,根据对象的类型,我们转换成对某数据库表的操作,将对象的各属性值设置为表的字段值,当然也包括属性.当对象的字段类型和数据库表的字段类型有不一的时候我们需要自己处理一下.这样就相当于把对象保存在数据库中,实现了对象的持久化.而且在做了这些设计后,我们会发现,数据库操作的代码和业务逻辑的代码已经可以分的很开,这样正好符合MVC 的思想;MVC 持久化 ORM的完美结合;?
上面就是简单的实现了ORM.我们需要在系统中为每个表建立对应的类,并且编写各种数据转换的逻辑.当然,我们可以将所有的类继承自一个基类,一些数据库操作通过基类或在基类中组合其他的功能类来完成;但自己完成这些逻辑会有些问题,如:如果数据库换了,以前是MySql,现在改成Mssql,或Oracle等;因为每种数据库都有些特性,一些特定数据类型等;这时候我们就需要在系统中改动我们的数据库操作SQL;而且这些逻辑的开发花了大量的时间.
在J2EE体系结构中,许多中间件供应商提供了各个层次的中间件;如web端的strtus,tapestry,等MVC框架,业务层的spring等框架来实现IOC,当然在EIS(企业级信息系统),当然也有,如: hibernate,jboss等;它们就是用来实现ORM的.?
使用hibernate要先导入hibernate的几个包,以及其依赖的其他包.然后在系统中添加配置;配置分两种:1)hibernate.cfg.xml.配置全局的数据库连接,以及数据库和对象的映射;?2)Class.hbm.xml每个类对应一个配置文件,Class为类的名称;在这里要声明每个字段,以及其属性,以及可能存在的和其他类的一对多,多对一,多对多关系;?
相比自己的实现和hibernate实现,hibernate兼容更多数据库,当数据库更换的时候,我们不需要做修改.但自己实现的orm可能面临修改sql等情况;而且自己实现容易出bug而且要花大量的时间;hibernate有个功能是:直接从数据源中的数据表生成对应的java类和配置文件;所以这又简化了开发人员的操作;当然,如果项目需求变更频繁,那就要不停的更改配置文件,这是很要命的.?
hibernate将如何映射这些过程封装起来,然后给出一些接口,开发人员实际上使用的只有几个简单的类而已;它的核心接口有: Session、SessionFactory、Transaction、Query和Configuration。这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。?
Session接口:Session接口负责执行被持久化对象的CRUD--增加(Create)、查询(Retrieve),更新(Update), 删除(Delete)操作;但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session.?
SessionFactory接口:SessionFactroy接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。所以我们可以用单件模式获得也可以在系统中定义一个static且final的变量;
Configuration接口:Configuration接口负责配置并启动Hibernate,创建SessionFactory对象。在Hibernate的启动的过程中,Configuration类的实例首先定位映射文档位置、读取配置,然后创建SessionFactory对象。
Transaction接口:Transaction接口负责事务相关的操作。它是可选的,开发人员也可以设计编写自己的底层事务处理代码。?
Query和Criteria接口:Query和Criteria接口负责执行各种数据库查询,它可以使用HQL或SQL两种表达方式;HQL是hibernate在SQL基础上开发出来的一种语言,它实际上就相当于把SQL封装了一次,让开发人员更容易理解;
持久化类的四个原则:1)对象必须有个不带参数的构造函数;因为在hibernate中会调用类的:Constructor.newInstance().所以至少要有一个包内可见的构造函数;2)有一个识别属性(可自由选择).属性的名称可以随便,但类型必须是原始类型.如: int.Long 等;3)最好将类设为:非final;或者实现一个方法全为public的interface.因为private方法默认的就是final的.最坏的情况,hibernate可以将final类进行持久化,但它不能实现别的接口;同时,也要避免在一个不是final的类里声明publicfinal 方法;如果要使用,则必须在配置文件里将:laze 设为 false;4)为字段声明get/set方法(可选).有些orm框架可以直接保存类的字段,但为了类的访问权限等关系.hibernate默认的是访问字段的getXX,isXX,setXX方法;所以最好还是将字段设为私有,然后声明public的get,set方法;