ITEEDU

第一个 Hibernate 程式

撰写本文的时候,Hibernate最新的版本是 3.1,请连接至 Hibernate的官方网站 进行档案的下载。 下载zip档案并解压缩之后,在解开的目录下就有Hibernate3.jar,这是Hibernate  3 所需要的API之 封装,可以在doc目录中找到API说明或相关参考文件,在lib  目录中的则是您可能会用到的相依 档案。

对于将撰写的第一个Hibernate程式,所需要的.jar档案除了hibernate3.jar之外,您还需要:

•      antlr‐2.7.6rc1.jar
•      asm.jar
•      cglib‐2.1.3.jar
•      commons‐collections‐2.1.1.jar
•      commons‐logging‐1.0.4.jar
•      dom4j‐1.6.1.jar、ehcache‐1.1.jar
•      jta.jar
•      log4j‐1.2.11.jar

Hibernate 在底层仍是使用 JDBC,所以您也必须要有 JDBC 的驱动程式的 jar 档案。 接来撰写个专案,示范一下 Hibernate 的功能与使用方式,在这个示范中暂时不使用到 Spring 的 功能,稍后会再来改写它,以了解 Spring 与 Hibernate 整合之后的方便性。同样的,先设计一个 User 类别,这个 User 类别将对应至 demo 资料库中的一个 user 表格:

•      User.java
package onlyfun.caterpillar;
public class User { 
	private Integer id; 
	private String name; 
	private Integer age;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

User 类别必须有一个 id 属性,用来作为物件于程式中唯一性的识别,这个 id 值可以由 Hibernate 为您产生。 在这边使用的 MySQL 资料库,表格建立时是使用以下的 SQL:

CREATE TABLE user ( 
		id INT(11) NOT NULL auto_increment PRIMARY KEY, 
		name VARCHAR(100) NOT NULL default '', 
		age INT 
) TYPE = InnoDB; 

User 类别与 user 表格之间要建立对映关系,实际上是靠一个映射文件来完成,映射文件可以使 用 XML 来撰写,通当命名为.hbm.xml,例如设计一个 User.hbm.xml 映射文件:

•      User.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/
→ hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="onlyfun.caterpillar.User" table="user">
		<id name="id" column="id">
			<generator class="native"/>
		</id>
		<property name="name" column="name"/>
		<property name="age" column="age"/>
	</class>
</hibernate-mapping>

在映射文件中,<class>标签用来定义类别与表格的对映,"name"属性用来设定类别名称,"table" 属性用来设定表格名称; <id>标签中"name"属性用来设定物件的唯一性识别 id,通常对应至资 料表中的主键栏位,也就是"column"属性所设定的对应栏 位;<generator>的"class"用来设定主键 的产生方式,设定为"native"表示依资料库自己的主键生成方式来生成主键值, 例如我的 user 表格在建立时,主键设定为 auto_increment,所以会每加入一笔资料后都自动递增主键值。

接下来的<property>标签则设定 User 物件的每一个属性(由"name"属性设定),分别对应至资料 库中 user 表格的哪一个栏位(由"column"属性设定)。 接着同样的,设计一个 IUserDAO 介面,让应用程式在存取资料库时,依赖于抽象的介面而非实 际的类别实作,如下所示:

•      IUserDAO.java
package onlyfun.caterpillar;
public interface IUserDAO {
	public void insert(User user);
	public User find(Integer id);
}

然后由 UserDAO 类别来实作 IUserDAO 介面,这次实作时使用 Hibernate 的 API,需要注入一个 org.hibernate.SessionFactory 物件:

•      UserDAO.java
package onlyfun.caterpillar;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public class UserDAO implements IUserDAO {
	private SessionFactory sessionFactory;
	public UserDAO() {
	}
	public UserDAO(SessionFactory sessionFactory) {
		this.setSessionFactory(sessionFactory);
	}
	public void setSessionFactory(
	SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	public void insert(User user) {
		// 取得 Session
		Session session = sessionFactory.openSession();
		// 开启交易
		Transaction tx= session.beginTransaction();
		// 直接储存物件
		session.save(user);
		// 送出交易 tx.commit(); session.close();
	}
	public User find(Integer id) {
		Session session = sessionFactory.openSession();
		User user = (User) session.get(User.class, id);
		session.close();
		return user;
	}
}

在 Hibernate 中,SessionFactory 是用来管理 org.hibernate.Session,Session 的作用类似于 JDBC 中 Connection 的作用,在 Hibernate 中每次进行资料存取之前都必须开启 Session,在进行资料变更 或储存时,则必须开启交易,在储存资 料的时候,您可以使用 Session 的 save()方法直接将物件 储存,在 org.hibernate.Transaction 执行 commit()方法 之后,Hibernate 会根据映射文件,将物件 中的各个属性资料转换并储存至 user 表格中对应的栏位。

在不使用资料库连线的时候,要记得使用 close()方法关闭 Session,关闭 Session 并不等于关闭 Connection,在 Hibernate 中如果您有使用连接池(Connection  pool),在 Session 的 close()方法 执行完毕后,会将 Connection 置回连接池之中,而不是直接关闭。

而在 UserDAO 的 find()方法实作中,您可以直接使用 Session 的 get()方法,指定资料的 id 值与要 封装资料的类别型态,接着查询回来的物件中就包括了相对应的资料,将之转换回 User 型态, 您就可以操作 User 物件上各种方法来取得资料。

在使用 Hibernate 时,还必须定义一个设定档,告知资料库名称、使用者名称、密码、映射文件 位置等,可以使用 XML 档案来定义,档名为 hibernate.cfg.xml,如下所示:

•      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="show_sql">
			true
		</property>
		<property name="dialect">
			org.hibernate.dialect.MySQLDialect
		</property>
		<property name="connection.driver_class">
			com.mysql.jdbc.Driver
		</property>
		<property name="connection.url">
			jdbc:mysql://localhost/demo
		</property>
		<property name="connection.username">
			caterpillar
		</property>
		<property name="connection.password">
			123456
		</property>
		<!-- 以下设置物件与资料库表格映射文件 -->
		<mapping resource="onlyfun/caterpillar/User.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

在<session‐factory>的设定中,"show_sql"被设定为 true,表示在执行资料库存取动作时显示 Hibernate  所生成、使用的 SQL  语法;Hibernate  可以使用许多不同的资料库,不同的资料库在 SQL 或操作上会有所差别,可以设定"dialect"来表示将 使用哪一种资料库适用的语句操作,由于 这边所使用的是 MySQL  资料库,所以设定为 org.hibernate.dialect.MySQLDialect ;接着来的 "connection.driver_class"、 "connection.url"、"connection.username"、"connection.password"分别 用以设定 JDBC 驱动 程式类别、URL、使用者名称与密码。

在<mapping> 中的"resource" 设定的是物件与资料库表格的映射文件位置,在上面的设定为 onlyfun/caterpillar/User.hbm.xml,表示档案在 Classpath 路径下的 onlyfun 资料夹的 caterpillar 资 料夹下,通常 hbm.xml 建议与对应的 Java 类别放置在一起。

接着就是建立 org.hibernate.cfg.Configuration 物件来读取设定档,它是 hibernate.cfg.xml 中相关设 定的具 体代表物件,Configuration 物件建立之后就不会变动,如果您修改了设定档案的内容, 则必须另外再产生新的 Configuration 物件,新 的变更才会被再次读取。

直接来看一个简单的程式,了解如何使用以上设计的程式进行资料的储存与查询:

•      HibernateDemo.java
package onlyfun.caterpillar;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateDemo {
	public static void main(String[] args) {
		// Configuration 负责管理 Hibernate 配置讯息 Configuration config =
		new Configuration().configure();
		// 根据 config 建立 SessionFactory
		// SessionFactory 将用于建立 Session
		SessionFactory sessionFactory =	config.buildSessionFactory();
		// 建立 DAO 物件
		IUserDAO userDAO = new UserDAO(sessionFactory);
		User user = new User(); 
		user.setName("caterpillar"); 
		user.setAge(new Integer(30));
		userDAO.insert(user);
		user = userDAO.find(new Integer(1));
		System.out.println("name: " + user.getName());
	}
}

在建立Configuration物件之后,就可以使用它当中所包括的资讯来建立SessionFactory物件,接着 在建立UserDAO时将SessionFactory的实例指定给它,然后您就可以操作UserDAO物件来进行资料 的储存了。 有关于Hibernate更详尽的介绍,可以参考 Hibernate。