撰写本文的时候,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 表格:
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 映射文件:
<?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 介面,让应用程式在存取资料库时,依赖于抽象的介面而非实 际的类别实作,如下所示:
package onlyfun.caterpillar; public interface IUserDAO { public void insert(User user); public User find(Integer id); }
然后由 UserDAO 类别来实作 IUserDAO 介面,这次实作时使用 Hibernate 的 API,需要注入一个 org.hibernate.SessionFactory 物件:
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,如下所示:
<?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 物件,新 的变更才会被再次读取。
直接来看一个简单的程式,了解如何使用以上设计的程式进行资料的储存与查询:
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。