Java中常用的两个ORM框架:Hibernate和iBatis

来源:互联网 发布:数据统计的目的 编辑:程序博客网 时间:2024/06/01 08:28

出处:http://wing011203.cnblogs.com/

http://www.cnblogs.com/wing011203/archive/2013/05/13/3075467.html

这篇文章里,我们主要讨论ORM框架,以及在使用上和JDBC的区别。

  概述

  ORM框架不是一个新话题,它已经流传了很多年。它的优点在于提供了概念性的、易于理解的数据模型,将数据库中的表和内存中的对象建立了很好的映射关系。

  我们在这里主要关注Java中常用的两个ORM框架:Hibernate和iBatis。下面来介绍这两个框架简单的使用方法,如果将来有时间,我会深入的写一些更有意思的相关文章。

  Hibernate

  Hibernate是一个持久化框架和ORM框架,持久化和ORM是两个有区别的概念,持久化注重对象的存储方法是否随着程序的退出而消亡ORM关注的是如何在数据库表和内存对象之间建立关联

  Hibernate使用POJO来表示Model,使用XML配置文件来配置对象和表之间的关系,它提供了一系列API来通过对对象的操作而改变数据库中的过程

  Hibernate更强调如何对单条记录进行操作,对于更复杂的操作,它提供了一种新的面向对象的查询语言:HQL。

  我们先来定义一个关于Hibernate中Session管理的类,这里的Session类似于JDBC中的Connection。

复制代码
 1 public class HibernateSessionManager { 2  3     private static SessionFactory sessionFactory; 4      5     static 6     { 7         try 8         { 9             sessionFactory = new Configuration().configure("sample/orm/hibernate/hibernate.cfg.xml").buildSessionFactory();10         }11         catch(Exception ex)12         {13             ex.printStackTrace();14         }15     }16     17     public static final ThreadLocal tl = new ThreadLocal();18     19     public static Session currentSession()20     {21         Session s = (Session)tl.get();22         if (s == null)23         {24             s = sessionFactory.openSession();25             tl.set(s);26         }27         28         return s;29     }30     31     public static void closeSession()32     {33         Session s = (Session)tl.get();34         tl.set(null);35         if (s != null)36         {37             s.close();38         }39     }40 }
复制代码

  基于单张表进行操作

  下面我们来看一个简单的示例,它沿用了Java回顾之JDBC中的数据库,使用MySQL的test数据库中的user表。

  首先,我们来定义VO对象:

定义User对象

  然后,我们定义User对象和数据库中user表之间的关联,user表中只有两列:id和name。

复制代码
 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4  5 <hibernate-mapping> 6     <class name="sample.orm.hibernate.User" table="user" catalog="test"> 7         <id name="userID" type="java.lang.Integer"> 8             <column name="id" /> 9             <generator class="assigned" />10         </id>11         <property name="userName" type="java.lang.String">12             <column name="name" />13         </property>14     </class>15 </hibernate-mapping>
复制代码

  将上述内容存储为User.hbm.xml。

  接下来,我们需要定义一个关于Hibernate的全局配置文件,这里文件名是hibernate.cfg.xml。

复制代码
 1 <?xml version='1.0' encoding='UTF-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3           "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4           "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5  6 <hibernate-configuration> 7     <session-factory> 8         <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 9         <property name="connection.url">jdbc:mysql://localhost/test</property>10         <property name="connection.username">root</property>11         <property name="connection.password">123</property>    12         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>13         <property name="show_sql">true</property>14         <property name="jdbc.fetch_size">50</property>15         <property name="jdbc.batch_size">25</property>16         17         <mapping resource="sample/orm/hibernate/User.hbm.xml" />        18     </session-factory>19 </hibernate-configuration>
复制代码

  可以看到,上述配置文件中包含了数据库连接的信息,诸如driver信息、数据库url、用户名、密码等等,还包括了我们上面定义的User.hbm.xml。

  最后,我们编写测试代码,来对user表进行增、删、查、改的操作:

使用Hibernate对user表进行操作

  我们按照如下顺序调用测试代码:

1 insertUser();2 updateUser(6);3 deleteUser(6);

  可以看到如下结果:

复制代码
=====Insert test=====Hibernate: insert into test.user (name, id) values (?, ?)=====Query test=====Hibernate: select user0_.id as id0_, user0_.name as name0_0_ from test.user user0_ where user0_.id=?ID:6; Name:Zhang Fei=====Update test=====Hibernate: select user0_.id as id0_, user0_.name as name0_0_ from test.user user0_ where user0_.id=?=====Before Update=====ID:6; Name:Zhang FeiHibernate: update test.user set name=? where id=?=====After Update=====ID:6; Name:Devil=====Delete test=====Hibernate: select user0_.id as id0_, user0_.name as name0_0_ from test.user user0_ where user0_.id=?=====Before Delte=====ID:6; Name:DevilHibernate: delete from test.user where id=?Hibernate: select user0_.id as id0_, user0_.name as name0_0_ from test.user user0_ where user0_.id=?=====After Delete=====Delete successfully.
复制代码

  请注意,上面的结果中,输出了每次数据库操作时的SQL语句,这是因为在配置文件中有如下配置:

<property name="show_sql">true</property>

  我们可以在开发调试阶段将其打开,在部署到客户方时,将其关闭。

  基于多表关联的操作

  Hibernate在建立多表关联时,根据主外键的设置,表之间的关联可以分为三种:一对一、一对多和多对多。这些关联会体现在表的配置文件以及VO中。

  下面我们来看一个经典的多表关联示例:排课表。数据库中建立如下四张表:Grade/Class/ClassRoom/Schedule。刚发现,使用MySQL自带的管理器导出表定义基本是一件不可能的任务。。。。

  上述各表除ID以及必要外键外,只有Name一列。

  然后看各个VO的定义:

定义Grade对象
定义Class对象
定义ClassRoom对象
定义Schedule对象

  接着是各个表的关联配置文件:

  1)Grade.hbm.xml

复制代码
 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4  5 <hibernate-mapping> 6     <class name="sample.orm.hibernate.Grade" table="grade" catalog="test"> 7         <id name="gradeID" type="java.lang.Integer"> 8             <column name="gradeid" /> 9             <generator class="assigned" />10         </id>11         <property name="gradeName" type="java.lang.String">12             <column name="gradename" />13         </property>14         15         <set name="classes" lazy="true" inverse="true" cascade="all-delete-orphan">16             <key>17                 <column name="gradeid"/>18             </key>19             <one-to-many class="sample.orm.hibernate.Class"/>20         </set>21     </class>22 </hibernate-mapping>
复制代码

  注意上面的<set>配置,里面的<one-to-many>节点说明了Grade和Class之间一对多的关系。

  2)Class.hbm.xml

复制代码
 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4  5 <hibernate-mapping> 6     <class name="sample.orm.hibernate.Class" table="class" catalog="test"> 7         <id name="classID" type="java.lang.Integer"> 8             <column name="classid" /> 9             <generator class="assigned" />10         </id>11         <property name="className" type="java.lang.String">12             <column name="classname" />13         </property>14         15         <many-to-one name="grade" class="sample.orm.hibernate.Grade" lazy="proxy" not-null="true">16             <column name="gradeid"/>17         </many-to-one>18         19         <set name="classrooms" lazy="true" inverse="true" cascade="all-delete-orphan" table="schedule">20             <key column ="classid"/>21             <many-to-many class="sample.orm.hibernate.ClassRoom" column="classroomid"/>22         </set>23     </class>24 </hibernate-mapping>
复制代码

  注意它定义两个关联:一个是和Grade之间多对一的关系,一个适合ClassRoom之间多对多的关系。

  3)ClassRoom.hbm.xml

复制代码
 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4  5 <hibernate-mapping> 6     <class name="sample.orm.hibernate.ClassRoom" table="classroom" catalog="test"> 7         <id name="classRoomID" type="java.lang.Integer"> 8             <column name="classroomid" /> 9             <generator class="assigned" />10         </id>11         <property name="classRoomName" type="java.lang.String">12             <column name="classroomname" />13         </property>14         15         <set name="classes" lazy="true" inverse="true" cascade="all-delete-orphan" table="schedule">16             <key column="classroomid"/>17             <many-to-many class="sample.orm.hibernate.Class" column="classid"/>18         </set>19     </class>20 </hibernate-mapping>
复制代码

  它只定义了一个关联:和Class之间的多对多关联。

  4)Schedule.hbm.xml

复制代码
 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4  5 <hibernate-mapping> 6     <class name="sample.orm.hibernate.Schedule" table="schedule" catalog="test"> 7         <id name="scheduleID" type="java.lang.Integer"> 8             <column name="scheduleid" /> 9             <generator class="assigned" />10         </id>11         <property name="classID" type="java.lang.Integer">12             <column name="classid" />13         </property>14         <property name="classRoomID" type="java.lang.Integer">15             <column name="classroomid" />16         </property>17     </class>18 </hibernate-mapping>
复制代码

  这里就不需要再定义关联了。

  我们需要在Hibernate全局配置文件中添加如下内容:

1 <mapping resource="sample/orm/hibernate/Grade.hbm.xml" />2 <mapping resource="sample/orm/hibernate/Class.hbm.xml" />3 <mapping resource="sample/orm/hibernate/ClassRoom.hbm.xml" />4 <mapping resource="sample/orm/hibernate/Schedule.hbm.xml" />

  下面是各种测试方法,在有关联的情况下,Hibernate提供了下面几个特性:

  • 延迟加载
  • 级联添加
  • 级联修改
  • 级联删除
多表关联情况下的一些测试方法

  按顺序调用上面的方法:

复制代码
1 getClass(1);2 getSchedule(1);3 insertGrade();4 updateGrade1(4);5 updateGrade2(4);6 deleteGrade(10);
复制代码

  执行结果如下:

复制代码
=====Get Class info=====Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?年级:一年级包括以下班级:一年级二班一年级一班Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?ID:1; Name:一年级Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?一年级一班使用以下教室:Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?教室二教室五教室一一年级二班使用以下教室:Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?教室四教室二教室六Hibernate: select class_.classid, class_.classname as classname2_, class_.gradeid as gradeid2_ from test.class class_ where class_.classid=?Hibernate: select class_.classid, class_.classname as classname2_, class_.gradeid as gradeid2_ from test.class class_ where class_.classid=?Hibernate: insert into test.grade (gradename, gradeid) values (?, ?)Hibernate: insert into test.class (classname, gradeid, classid) values (?, ?, ?)Hibernate: insert into test.class (classname, gradeid, classid) values (?, ?, ?)=====Get Class info=====Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?年级:四年级包括以下班级:四年级二班四年级一班Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?ID:4; Name:四年级Hibernate: update test.grade set gradename=? where gradeid=?=====Get Class info=====Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?年级:Grade 4包括以下班级:Grade 4二班Grade 4一班Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?ID:4; Name:Grade 4Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?Hibernate: delete from test.class where classid=?Hibernate: delete from test.class where classid=?Hibernate: delete from test.grade where gradeid=?Hibernate: select class_.classid, class_.classname as classname2_, class_.gradeid as gradeid2_ from test.class class_ where class_.classid=?Hibernate: select class_.classid, class_.classname as classname2_, class_.gradeid as gradeid2_ from test.class class_ where class_.classid=?Hibernate: insert into test.grade (gradename, gradeid) values (?, ?)Hibernate: insert into test.class (classname, gradeid, classid) values (?, ?, ?)Hibernate: insert into test.class (classname, gradeid, classid) values (?, ?, ?)Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?删除成功=====Get Class info=====Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?年级:Grade 4包括以下班级:Grade 4一班Grade 4二班Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?Hibernate: select classes0_.gradeid as gradeid1_, classes0_.classid as classid1_, classes0_.classid as classid0_, classes0_.classname as classname2_0_, classes0_.gradeid as gradeid2_0_ from test.class classes0_ where classes0_.gradeid=?Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?Hibernate: select classrooms0_.classid as classid1_, classrooms0_.classroomid as classroo2_1_, classroom1_.classroomid as classroo1_0_, classroom1_.classroomname as classroo2_4_0_ from schedule classrooms0_ inner join test.classroom classroom1_ on classrooms0_.classroomid=classroom1_.classroomid where classrooms0_.classid=?Hibernate: delete from test.class where classid=?Hibernate: delete from test.class where classid=?Hibernate: delete from test.grade where gradeid=?Hibernate: select grade0_.gradeid as gradeid0_, grade0_.gradename as gradename1_0_ from test.grade grade0_ where grade0_.gradeid=?删除成功
复制代码

  同样,执行结果中包含了各个SQL语句。

  iBatis

  iBatis是另外一种ORM框架,和Hibernate擅长操作单条记录不同,iBatis是基于SQL模板的可以说,iBatis每次和数据库进行操作时,都有明确的SQL语句,而这些SQL语句,就是我们定义在配置文件中的

  我们还是以test数据库中的user表为例,简单说明iBatis的操作流程:

  首先,我们还是需要定义VO对象,这里还是使用和Hibernate讲解时相同的User:

定义User对象

  然后需要针对这个VO,定义一个独立的配置文件:User.xml

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE sqlMap  3     PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"  4     "http://www.ibatis.com/dtd/sql-map-2.dtd"> 5      6 <sqlMap namespace="User"> 7  8     <typeAlias alias="user" type="sample.orm.ibatis.User" /> 9     10     11     <cacheModel id="user-cache" type="OSCache" readOnly="true" serialize="true">12         <flushInterval milliseconds="1" />13         <flushOnExecute statement="insertUser" />14         <flushOnExecute statement="updateUser" />15         <flushOnExecute statement="getUser" />16         <flushOnExecute statement="getAllUser" />17         <property value="1" name="size" />18      </cacheModel>19     20     <!--21     <resultMap >22         <result property="userID" column="id" />23         <result property="userName" column="name" />24     </resultMap>25     -->26     27     28     <select id="getUser" parameterClass="java.lang.Integer" resultClass="user" cacheModel="user-cache" >29         select id as userID,name as userName from user where id = #userID#30     </select>31     <select id="getAllUser" resultClass="user" cacheModel="user-cache">32         select id as userID,name as userName from user33     </select>34     <update id="updateUser" parameterClass="user">35         update user SET name=#userName# WHERE id = #userID#36     </update>37     <insert id="insertUser" parameterClass="user">38         insert into user ( id, name ) VALUES ( #userID#,#userName#)39     </insert>40     <delete id="deleteUser" parameterClass="java.lang.Integer">41         delete from user where id=#userID#42     </delete>43     44 </sqlMap>
复制代码

  这个配置文件主要包括三部分:

  1)缓存的配置

  2)对象属性和表字段之间的关联

  3)针对表的各种CRUD操作

  然后是关于iBatis的全局配置文件SqlMapConfig.xml:

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE sqlMapConfig  3     PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"  4     "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> 5      6 <sqlMapConfig> 7  8     <settings cacheModelsEnabled="true" enhancementEnabled="true" 9         lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32"10         maxSessions="10" maxTransactions="5" useStatementNamespaces="false" />11         12     <transactionManager type="JDBC">13         <dataSource type="SIMPLE">14            <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />15            <property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost/test" />16            <property name="JDBC.Username" value="root" />17            <property name="JDBC.Password" value="123" />18            <property name="Pool.MaximumActiveConnections" value="10" />19            <property name="Pool.MaximumIdleConnections" value="5" />20            <property name="Pool.MaximumCheckoutTime" value="120000" />21            <property name="Pool.TimeToWait" value="500" />22            <property name="Pool.PingQuery" value="select 1 from user" />23            <property name="Pool.PingEnabled" value="false" />24         </dataSource>25     </transactionManager>26     27     <sqlMap resource="sample/orm/ibatis/User.xml" />28 29 </sqlMapConfig>
复制代码

  和Hibernate全局配置文件类似,它也包含了数据库连接的信息、数据库连接池的信息以及我们定义的User.xml。

  下面是测试方法:

iBatis测试方法

  它的执行结果如下:

复制代码
=====user info=====ID:1;Name:Zhang SanID:2;Name:TEST=====Insert test==========user info=====ID:10;Name:Angel=====Update test==========user info=====ID:10;Name:Devil=====Delete test==========user info=====ID:1;Name:Zhang SanID:2;Name:TEST
复制代码

  这篇文章只是简单介绍了Hibernate和iBatis的用法,并没有涉及全部,例如Hibernate的事务、拦截、HQL、iBatis的缓存等等。这里主要是为了描述ORM框架的基本轮廓,以及在使用方式上它和JDBC的区别。

0 0
原创粉丝点击