37.3 一个简单的Hibernate实例(V005)
37.3.1 创建Hibernate配置文件:hibernate.cfg.xml
在“Java Resourcess:src”下创建一个hibernate.cfg.xml文件如下。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库 -->
<property name="connection.datasource">java:comp/env/jdbc/mysql</property>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<!-- 打开Hibernate的session自动管理机制 -->
<property name="current_session_context_class">thread</property>
<!-- 把所有*.hbm.xml文件注册在这里 -->
<mapping resource="cn/com/chengang/sms/model/model.hbm.xml"/>
</session-factory>
</hibernate-configuration>
配置说明:
● connection.datasource设定所用的连接池。
● dialect告诉Hibernate使用哪种SQL数据库方言(dialect)。不同数据库的SQL语法都有一些差异,Hibernate会根据设置的方言来适应这些差异。想知道其他数据的方言名称,可以利用Eclipse的代码提示功能,在Java程序中输入“org.hibernate.dialect.”然后按“Alt+/”快捷键。
● show_sql设定在控制台是否显示Hibernate生成的SQL语句,开发期间设为true,便于调试。
● model.hbm.xml是一个XML映射文件,这个文件创建在model目录下(内容将在以后给出)。注意,这里用的是相对路径,cn字串前面是没有“/”的。
● hibernate.cfg.xml还有一种hibernate.properties的写法,在Hibernate的解压目录etc可找到它的例子。两种写法选一种即可,本文选前一种。
● 某些属性对Hibernate的性能影响很大,比如batch_size项设置成0和30,性能相差会有4倍以上。属性会有一个默认值,但如果所开发的项目需要作性能优化,则可根据实际情况来重新设置。如果想了解hibernate.cfg.xml中更多的属性设置,可以参考Hibernate文档的“表3.3 Hibernate配置属性”,那里有属性的说明和建议值,本文不再复述。
37.3.2 创建XML映射文件:model.hbm.xml
Hibernate之所以能够智能地判断实体类和数据表之间的对应关系,就是因为有XML映射文件。本小节先在cn.com.chengang.sms.model包下创建一个名为model.hbm.xml的XML映射文件,其内容如下。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.com.chengang.sms.model.Grade" table="grade">
<id name="id">
<generator class="identity"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
配置说明:
● model.hbm.xml可以任意命名及放置于其他目录下,当然hibernate.cfg.xml文件也要做相应修改。笔者建议将它和它所对应的实体类放在一个包下,并用包名做文件名。
● <class>项定义了实体类和数据表之间的关系:name是实体类(用类全名),table是对应的数据表(表名不分大小写)。可以省略掉table属性,这时默认表名和实体类同名。在model.hbm.xml文件中可以设置多个<class>项,笔者建议将一个包中的所有实体类都集中在一个*.hbm.xml文件中。
● <id>项定义了主键id字段所用的键值生成方法,identity是一种MSSQL、DB2、MySQL通用的主键值生成方法(Oracle不能用identity,可换成sequence)。要了解更多内容,可以查阅Hibernate文档。
● <property>子项定义了实体类和表字段的关联。本例只设置了定义类字段的name属性,还有一个column属性是定义数据库表字段名的,本例没有设置。Hibernate正是通过这里的设置建立起实体类和数据库表之间的字段对应关系。本例没有设置column,则Hibernate会默认为它和name属性同名。假如,想将Grade实体类的name字段对应于数据库表的grade_name字段,并将表字段的长度定义成16、不允许空值,则可以按照如下设置:
<property name="name">
<column name="grade_name" length="16" not-null="true"/>
</property>
● <property>体现Hibernate的友好性:它可以设置得很详细,也可以很简洁,当设置简洁时,Hibernate会采用默认值。要了解更多关于<property>设置的内容,可以参阅Hibernate文档。
37.3.3 创建HibernateUtil类
HibernateUtil类用于得到一个SessionFactory,而SessionFactory可以得到Session。Session是Hibernate中最重要和使用最频繁的一个对象,实体对象都是通过它来和数据库交互。这个Session和JSP的Session不同,但是有一点类似于JDBC的Connection,即Session比Connection包含的内容更多,功能范围更广。在Hibernate的编程中将不会再使用Connection,而是通过Session来和数据库交互。
HibernateUtil类的内容如下:
package cn.com.chengang.sms.db;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// 实例化一个SessionFactory对象
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
程序说明:
● HibernateUtil可以任意取名。它是一个静态方法类,即类中的方法都是静态方法。
● SessionFactory是一个静态变量,它由static {…}静态代码块来初始化一个实例。注意,static{…}代码块比较特殊,它既不是方法也不是变量。生成一个SessionFactory对象很耗费时间和资源,所以在这里整个Web系统共用一个SessionFactory。而生成一个Session对象的代价很小,在编程中千万不要把Session写成单例模式来进行实例共享,对Session的使用原则是用完就关闭,而且要尽量早关闭。
● 对于旧版本的Hibernate,此类还有将Session保存/剥离到当前线程中的两个方法。但现在已经不需要了,因为这里在新版本的hibernate.cfg.xml中用current_session _context_class属性打开了Hibernate的Session自动管理机制。
37.3.4 创建GradeManager类
GradeManager类似于DbOperate,它主要提供数据库操作方法。在这里编写了向Grade表插入一条记录的方法,以及取出Grade表中id值大于2的所有记录的方法。代码如下:
package cn.com.chengang.sms.db;
public class GradeManager {
public void insertGrade() throws HibernateException {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Grade grade = new Grade();// 生成一个年级对象
grade.setName("高四");
session.save(grade); // 将这个对象保存到数据库
session.getTransaction().commit();
}
public List<Grade> getGrades() throws HibernateException {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
// 创建一个条件查询语句
String hql = "from Grade as g where g.id > :id";
Query query = session.createQuery(hql); // 创建查询对象
query.setInteger("id", 2); // 设置查询参数
List<Grade> result = query.list(); // 从数据库取出数据,并自动封装到List集合中
//也可以三句合为一句:session.createQuery(hql).setInteger("id", 2).list();
session.getTransaction().commit();// 提交
return result;// 返回数据集
}
public void close(){
HibernateUtil.getSessionFactory().close();
}
}
程序说明:
● 在Session中,每个数据库操作都是在一个事务(Transaction)中进行的,这样可以隔离开不同的操作。Hibernate的事务是JDBC事务的更高层次的抽象,它提供了更好的灵活性和适应性。
● 无论session.getTransaction().commit()提交,或session.getTransaction().rollback()回滚都会自动关闭session。
● 以前都是将实体对象的字段一个个拆散并组合成SQL语句,或者从数据库取出数据后将字段值一个个封装到实体对象。现在用了Hibernate,就再也不必这么处理数据了,这是Hibernate有魅力的一面。
● getGrades方法中用到的hql字串不是JDBC的SQL语句,而是Hibernate自有的HQL语句。关于HQL的更多内容,可查阅Hibernate文档。
37.3.5 创建hibernateTest.jsp
hibernateTest.jsp使用GradeManager类来获得数据,并将数据显示在页面上。代码如下:
<%@ page contentType="text/html; charset=utf8"%>
<%@ page import="cn.com.chengang.sms.db.GradeManager"%>
<%@ page import="cn.com.chengang.sms.model.Grade"%>
<%
GradeManager mgr = new GradeManager();
//插入一个年级对象
mgr.insertGrade();
//取出所有年级对象,并显示在页面上
for (Grade g : mgr.getGrades())
out.print(g.getId() + " " + g.getName() + "</br>");
mgr.close();
%>
37.3.6 总结及实践建议
以上5步完成了一个简单的Hibernate实例,用浏览器运行hibernateTest.jsp的效果如 图37.5所示。
图37.5 hibernateTest.jsp的运行效果
本节用从底层到高层的次序来完成了一个实例的讲解,它虽然简单,但也反映了一个典型Hibernate程序的编写框架:
● HibernateUtil一经完成之后即可系统通用,以后很少改动。
● XML映射文件是项目前期要做的最重要的工作,在项目开发后期就很少会改动它。对初学者来说,编写XML映射文件也是难点所在。
● GradeManager是数据库操作类,这相当于以前的DbOperate类的功能。但它不再直接操作数据库,而是通过Hibernate去访问,所以在GradeManager类中看不到涉及JDBC的代码。
● 最后,就是位于最高层的JSP文件hibernateTest.jsp,这个文件主要使用GradeManager类来操作数据库。
实践建议:
● Lomboz支持XML映射文件的热修改,当XML映射文件改动之后,Lomboz会将它重新装入。不过这可能需要一两秒钟时间,具体时间要视读者所用电脑性能 而定。
● 在Java编程中要时刻注意区分大小写,这是编程中出错较多的原因。