Java回顾之ORM框架
这篇文章里,我们主要讨论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对象:

1 public class User implements Serializable
2 {
3 private static final long serialVersionUID = 1L;
4 private int userID;
5 private String userName;
6 public void setUserID(int userID) {
7 this.userID = userID;
8 }
9 public int getUserID() {
10 return userID;
11 }
12 public void setUserName(String userName) {
13 this.userName = userName;
14 }
15 public String getUserName() {
16 return userName;
17 }
18 }
然后,我们定义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表进行增、删、查、改的操作:

1 private static void getUser(int id)
2 {
3 Session session = HibernateSessionManager.currentSession();
4 System.out.println("=====Query test=====");
5 User user = (User)session.get(User.class, new Integer(id));
6 if (user != null)
7 {
8 System.out.println("ID:" + user.getUserID() + "; Name:" + user.getUserName());
9 }
10 HibernateSessionManager.closeSession();
11 }
12
13 private static void insertUser()
14 {
15 Session session = HibernateSessionManager.currentSession();
16 System.out.println("=====Insert test=====");
17 Transaction transaction = session.beginTransaction();
18 User user = new User();
19 user.setUserID(6);
20 user.setUserName("Zhang Fei");
21 session.save(user);
22 session.flush();
23 transaction.commit();
24 HibernateSessionManager.closeSession();
25 getUser(6);
26 }
27
28 private static void updateUser(int id)
29 {
30 Session session = HibernateSessionManager.currentSession();
31 System.out.println("=====Update test=====");
32 Transaction transaction = session.beginTransaction();
33 User user = (User)session.get(User.class, new Integer(id));
34 System.out.println("=====Before Update=====");
35 if (user != null)
36 {
37 System.out.println("ID:" + user.getUserID() + "; Name:" + user.getUserName());
38 }
39 user.setUserName("Devil");
40 session.save(user);
41 session.flush();
42 transaction.commit();
43 user = (User)session.get(User.class, new Integer(id));
44 System.out.println("=====After Update=====");
45 if (user != null)
46 {
47 System.out.println("ID:" + user.getUserID() + "; Name:" + user.getUserName());
48 }
49 HibernateSessionManager.closeSession();
50 }
51
52 private static void deleteUser(int id)
53 {
54 Session session = HibernateSessionManager.currentSession();
55 System.out.println("=====Delete test=====");
56 Transaction transaction = session.beginTransaction();
57 User user = (User)session.get(User.class, new Integer(id));
58 System.out.println("=====Before Delte=====");
59 if (user != null)
60 {
61 System.out.println("ID:" + user.getUserID() + "; Name:" + user.getUserName());
62 }
63 session.delete(user);
64 transaction.commit();
65 user = (User)session.get(User.class, new Integer(id));
66 System.out.println("=====After Update=====");
67 if (user != null)
68 {
69 System.out.println("ID:" + user.getUserID() + "; Name:" + user.getUserName());
70 }
71 else
72 {
73 System.out.println("Delete successfully.");
74 }
75 HibernateSessionManager.closeSession();
76 }
我们按照如下顺序调用测试代码:
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 Fei
Hibernate: 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:Devil
Hibernate: 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的定义:

1 package sample.orm.hibernate;
2
3 import java.io.Serializable;
4 import java.util.Set;
5
6 public class Grade implements Serializable
7 {
8 private static final long serialVersionUID = 1L;
9 private int gradeID;
10 private String gradeName;
11 private Set classes;
12 public void setGradeID(int gradeID) {
13 this.gradeID = gradeID;
14 }
15 public int getGradeID() {
16 return gradeID;
17 }
18 public void setGradeName(String gradeName) {
19 this.gradeName = gradeName;
20 }
21 public String getGradeName() {
22 return gradeName;
23 }
24 public void setClasses(Set classes) {
25 this.classes = classes;
26 }
27 public Set getClasses() {
28 return classes;
29 }
30 }

1 package sample.orm.hibernate;
2
3 import java.io.Serializable;
4 import java.util.Set;
5
6 public class Class implements Serializable
7 {
8 private static final long serialVersionUID = 1L;
9 private int classID;
10 private Grade grade;
11 private Set classrooms;
12 private String className;
13 public void setClassID(int classID) {
14 this.classID = classID;
15 }
16 public int getClassID() {
17 return classID;
18 }
19 public void setClassName(String className) {
20 this.className = className;
21 }
22 public String getClassName() {
23 return className;
24 }
25 public void setGrade(Grade grade) {
26 this.grade = grade;
27 }
28 public Grade getGrade() {
29 return grade;
30 }
31 public void setClassrooms(Set classrooms) {
32 this.classrooms = classrooms;
33 }
34 public Set getClassrooms() {
35 return classrooms;
36 }
37 }

1 package sample.orm.hibernate;
2
3 import java.io.Serializable;
4 import java.util.Set;
5
6 public class ClassRoom implements Serializable
7 {
8 private static final long serialVersionUID = 1L;
9 private int classRoomID;
10 private String classRoomName;
11 private Set classes;
12 public void setClassRoomID(int classRoomID) {
13 this.classRoomID = classRoomID;
14 }
15 public int getClassRoomID() {
16 return classRoomID;
17 }
18 public void setClassRoomName(String classRoomName) {
19 this.classRoomName = classRoomName;
20 }
21 public String getClassRoomName() {
22 return classRoomName;
23 }
24 public void setClasses(Set classes) {
25 this.classes = classes;
26 }
27 public Set getClasses() {
28 return classes;
29 }
30 }

1 package sample.orm.hibernate;
2
3 import java.io.Serializable;
4 import java.util.Set;
5
6 public class Schedule implements Serializable
7 {
8 private static final long serialVersionUID = 1L;
9 private int scheduleID;
10 private int classRoomID;
11 private int classID;
12 private Set classes;
13 public void setClassRoomID(int classRoomID) {
14 this.classRoomID = classRoomID;
15 }
16 public int getClassRoomID() {
17 return classRoomID;
18 }
19 public void setClassID(int classID) {
20 this.classID = classID;
21 }
22 public int getClassID() {
23 return classID;
24 }
25 public void setClasses(Set classes) {
26 this.classes = classes;
27 }
28 public Set getClasses() {
29 return classes;
30 }
31 public void setScheduleID(int scheduleID) {
32 this.scheduleID = scheduleID;
33 }
34 public int getScheduleID() {
35 return scheduleID;
36 }
37 }
接着是各个表的关联配置文件:
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 private static void getClass(int gradeid)
2 {
3 Session session = HibernateSessionManager.currentSession();
4 System.out.println("=====Get Class info=====");
5 Transaction transaction = session.beginTransaction();
6 Grade grade = (Grade)session.get(Grade.class, new Integer(gradeid));
7
8 Hibernate.initialize(grade);
9 Iterator iterator = grade.getClasses().iterator();
10 System.out.println("年级:" + grade.getGradeName() + "包括以下班级:");
11 while(iterator.hasNext())
12 {
13 System.out.println(grade.getGradeName() + ((Class)iterator.next()).getClassName());
14 }
15 HibernateSessionManager.closeSession();
16 }
17
18 private static void getSchedule(int gradeid)
19 {
20 Session session = HibernateSessionManager.currentSession();
21 Transaction transaction = session.beginTransaction();
22 Grade grade = (Grade)session.get(Grade.class, new Integer(gradeid));
23 if (grade != null)
24 {
25 System.out.println("ID:" + grade.getGradeID() + "; Name:" + grade.getGradeName());
26 }
27
28 Hibernate.initialize(grade.getClasses());
29
30 Iterator iterator = grade.getClasses().iterator();
31 while(iterator.hasNext())
32 {
33 Class c = (Class)iterator.next();
34 System.out.println(grade.getGradeName() + c.getClassName() + "使用以下教室:");
35 Hibernate.initialize(c.getClassrooms());
36 Iterator iterator1 = c.getClassrooms().iterator();
37 while(iterator1.hasNext())
38 {
39 System.out.println(((ClassRoom)iterator1.next()).getClassRoomName());
40 }
41 }
42 HibernateSessionManager.closeSession();
43 }
44
45 private static void insertGrade()
46 {
47 Session session = HibernateSessionManager.currentSession();
48 Transaction transaction = session.beginTransaction();
49 Grade grade = new Grade();
50 grade.setGradeID(4);
51 grade.setGradeName("四年级");
52
53 Class c1 = new Class();
54 c1.setClassID(7);
55 c1.setGrade(grade);
56 c1.setClassName("一班");
57 Class c2 = new Class();
58 c2.setClassID(8);
59 c2.setGrade(grade);
60 c2.setClassName("二班");
61
62 Set set = new HashSet();
63 set.add(c1);
64 set.add(c2);
65
66 grade.setClasses(set);
67
68 session.save(grade);
69 session.flush();
70 transaction.commit();
71 HibernateSessionManager.closeSession();
72 getClass(4);
73 }
74
75 private static void deleteGrade(int gradeid)
76 {
77 Session session = HibernateSessionManager.currentSession();
78 Transaction transaction = session.beginTransaction();
79 Grade grade = (Grade)session.get(Grade.class, new Integer(gradeid));
80 if (grade != null)
81 {
82 session.delete(grade);
83 session.flush();
84 }
85
86 transaction.commit();
87
88 grade = (Grade)session.get(Grade.class, new Integer(gradeid));
89 if (grade == null)
90 {
91 System.out.println("删除成功");
92 }
93 HibernateSessionManager.closeSession();
94 }
95
96 private static void updateGrade1(int gradeid)
97 {
98 Session session = HibernateSessionManager.currentSession();
99 Transaction transaction = session.beginTransaction();
100 Grade grade = (Grade)session.get(Grade.class, new Integer(gradeid));
101 if (grade != null)
102 {
103 System.out.println("ID:" + grade.getGradeID() + "; Name:" + grade.getGradeName());
104 }
105 grade.setGradeName("Grade " + gradeid);
106 session.save(grade);
107 session.flush();
108 transaction.commit();
109 HibernateSessionManager.closeSession();
110 getClass(gradeid);
111 }
112
113 private static void updateGrade2(int gradeid)
114 {
115 Session session = HibernateSessionManager.currentSession();
116 Transaction transaction = session.beginTransaction();
117 Grade grade = (Grade)session.get(Grade.class, new Integer(gradeid));
118 if (grade != null)
119 {
120 System.out.println("ID:" + grade.getGradeID() + "; Name:" + grade.getGradeName());
121 }
122
123 Grade newGrade = new Grade();
124 newGrade.setGradeID(10);
125 newGrade.setGradeName(grade.getGradeName());
126 Set set = grade.getClasses();
127 Set newSet = new HashSet();
128 Iterator iterator = set.iterator();
129 while(iterator.hasNext())
130 {
131 Class c = (Class)iterator.next();
132 Class temp = new Class();
133 temp.setClassID(c.getClassID());
134 temp.setClassName(c.getClassName());
135 temp.setGrade(newGrade);
136 newSet.add(temp);
137 }
138 newGrade.setClasses(newSet);
139 session.delete(grade);
140 session.flush();
141 session.save(newGrade);
142 session.flush();
143 transaction.commit();
144 grade = (Grade)session.get(Grade.class, new Integer(gradeid));
145 if (grade == null)
146 {
147 System.out.println("删除成功");
148 }
149 HibernateSessionManager.closeSession();
150 getClass(10);
151 }
按顺序调用上面的方法:
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 4
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 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:

1 package sample.orm.ibatis;
2
3 import java.io.Serializable;
4
5 public class User implements Serializable
6 {
7 private static final long serialVersionUID = 1L;
8 private int userID;
9 private String userName;
10 public void setUserID(int userID) {
11 this.userID = userID;
12 }
13 public int getUserID() {
14 return userID;
15 }
16 public void setUserName(String userName) {
17 this.userName = userName;
18 }
19 public String getUserName() {
20 return userName;
21 }
22
23 }
然后需要针对这个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 user
33 </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。
下面是测试方法:

1 public class Sample {
2
3 private SqlMapClient sqlMap = null;
4
5 private void buildMap() throws IOException
6 {
7 String resource = "sample/orm/ibatis/SqlMapConfig.xml";
8 Reader reader = Resources.getResourceAsReader(resource);
9 this.sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
10 }
11
12 private void insertUser() throws IOException, SQLException
13 {
14 System.out.println("=====Insert test=====");
15 if (this.sqlMap == null)
16 {
17 this.buildMap();
18 }
19 this.sqlMap.startTransaction();
20 User user = new User();
21 user.setUserID(10);
22 user.setUserName("Angel");
23
24 this.sqlMap.insert("insertUser", user);
25 this.sqlMap.commitTransaction();
26
27 user = getUser(10);
28 printUserInfo(user);
29 }
30
31 private void updateUser() throws IOException, SQLException, InterruptedException
32 {
33 System.out.println("=====Update test=====");
34 if (this.sqlMap == null)
35 {
36 this.buildMap();
37 }
38 this.sqlMap.startTransaction();
39 User user = new User();
40 user.setUserID(10);
41 user.setUserName("Devil");
42 this.sqlMap.update("updateUser", user);
43 this.sqlMap.commitTransaction();
44 this.sqlMap.flushDataCache();
45 // Thread.sleep(3000);
46 user = getUser(10);
47 printUserInfo(user);
48 }
49
50 private void deleteUser() throws IOException, SQLException
51 {
52 System.out.println("=====Delete test=====");
53 if (this.sqlMap == null)
54 {
55 this.buildMap();
56 }
57 sqlMap.flushDataCache();
58 this.sqlMap.startTransaction();
59 this.sqlMap.delete("deleteUser", 10);
60 this.sqlMap.commitTransaction();
61 getAllUser();
62 }
63
64 private User getUser(int id) throws IOException, SQLException
65 {
66 if (this.sqlMap == null)
67 {
68 this.buildMap();
69 }
70 User user = (User)this.sqlMap.openSession().queryForObject("getUser", id);
71
72 return user;
73 }
74
75 private List<User> getAllUser() throws IOException, SQLException
76 {
77 if(this.sqlMap==null)
78 this.buildMap();
79
80 List userList=null;
81 userList=this.sqlMap.openSession().queryForList("getAllUser");
82 printUserInfo(userList);
83 return userList;
84 }
85
86 private void printUserInfo(User user)
87 {
88 System.out.println("=====user info=====");
89 System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());
90 }
91
92 private void printUserInfo(List<User> users)
93 {
94 System.out.println("=====user info=====");
95 for(User user:users)
96 {
97 System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());
98 }
99 }
100
101 public static void main(String[] args) throws IOException, SQLException, InterruptedException
102 {
103 Sample sample = new Sample();
104 sample.getAllUser();
105 sample.insertUser();
106 sample.updateUser();
107 sample.deleteUser();
108 }
109 }
它的执行结果如下:
=====user info=====
ID:1;Name:Zhang San
ID: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 San
ID:2;Name:TEST
这篇文章只是简单介绍了Hibernate和iBatis的用法,并没有涉及全部,例如Hibernate的事务、拦截、HQL、iBatis的缓存等等。这里主要是为了描述ORM框架的基本轮廓,以及在使用方式上它和JDBC的区别。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!