引子
面向对象程序设计中对于类、继承、多态、组成、聚合等概念和关系数据中的表、主键、外键等概念并不能直接对应。想要将对象持久化到关系数据库库中,需要进行转换。
可以使用JDBC手动转换,不过工作量较大,不好维护。
更方便强大的是借助成熟的对象关系映射框架(ORM,Object Relation Mapping)的支持进行对象持久化。
Hibernate是一个流行的ORM框架,此外还有iBatis ,Apache OJB,TopLink等。项目地址为www.hibernate.org,很多内容详细的内容可供参考。
闲话不多说,从今天开始学起。
我们使用hibernate的目的就是希望将程序中众多对象及他们之间的关系在内存和数据库之间方便的转化。
换句话说,就是建立“内存对象”与“数据库记录“之间的”关系“。
其中”内存对象“在hibernate中被叫做实体对象,是与程序中的对象,承载着业务数据信息。
”数据库记录“是数据库表中的记录。
”关系“是一系列的配置文件,来告诉hibernate这些实体对象是按照怎么样的规则与数据库中的表记录进行关联的。
上一个小例子说明一下:
这里有一个应用系统,有一个实体类Event代表一个类似于聚会的集体活动。
Event的实体类其实就是一个普通的JavaBean。包含举办的时间(date)和活动主题(title)。
增加一个id作为标示符以便使用hibernate提供的很多特性。其中id的set方法被设置为private,因为我们并不希望出了hibernate以外的程序修改这个属性。请放心,无论是public、protected还是private修饰符都可以被hibernate访问到。
作为需要被持久化的实体类还需要拥有无参的构造函数以便hibernate通过反射机制构造这个对象。
package mypackage.domain; import java.util.Date; public class Event { private Long id; private String title; private Date date; public Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }Hibernate 需要知道怎样去加载(load)和存储(store)持久化类的对象。这正是 Hibernate 映射文件发挥作用的地方。映射文件告诉 Hibernate 它应该访问数据库(database)里面的哪个表(table)及应该使用表里面的哪些字段(column)。
我们建立一个名为Event.hbm.xml的映射文件(省略了xml的dtd声明)
package属性指定包名,name标签指定类名,table标签指定这个类对应的表名。如果不写table属性,默认的表名为类名+s。
<hibernate-mapping package="mypackage.domain"> <class name="Event" table="EVENTS"> </class> </hibernate-mapping >接下来配置实体类中的各个属性。id 元素是对标示符属性的声明。name标签说明当前要配置的属性名称是id并告诉Hibernate 使用 getId() 和 setId() 方法来访问这个属性。column 标签说明EVENTS表中的EVENT_ID字段与这个属性对应。<generator>标签来指定标示符的生成策略,后面会学到,在这里可以理解为有hibernate帮你生成这个值。
<class name="Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> </class>类中的其他属性如date和title属性使用<property>元素配置。
<property name="date" type="timestamp" column="EVENT_DATE"/> <property name="title" column="EVENT_TITLE"/>注意:date属性的type标签被设置为""timestamp"而title 属性没有配置type标签。我们在映射文件里type标签中填入的既不是Java 数据类型,也不是 SQL 数据库的数据类型,而是Hibernate 映射类型(mapping types)。即把在 Java 数据类型与 SQL 之间的类型。如果在映射文件中没有设置 type 属性的话,Hibernate 会自己试着去确定正确的转换类型和它的映射类型。某些情况下需要我们显式配置,如这里的date 属性就是个很好的例子,Hibernate 无法知道这个属性(java.util.Date 类型的)应该被映射成SQL类型中的 date(年月日),或 timestamp(年月日时分秒),还是 time(时分秒)。在此例中,把这个属性映射成 timestamp ,以便记录日期和时间。
想让hibernate运转起来,还需要对其进行简单的配置。其方法有三:程序配置,properties文件配置,xml文件配置。
一般来说习惯用xml配置功能强大又灵活。
<hibernate-configuration> <session-factory> <!-- 驱动 --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 数据库地址 --> <property name="hibernate.connection.url">jdbc:mysql:///test</property> <property name="connection.username">sa</property> <property name="connection.password">sa</property> <!-- SQL 方言 --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 打印SQL执行语句 --> <property name="show_sql">true</property> <!-- 以下是映射文件列表 --> <mapping resource="mypackage/domain/Event.hbm.xml"/> </session-factory> </hibernate-configuration >
package mypackage.util; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // configuration实例的configure()方法会调用classpath根目录下的hibernate.cfg.xml文件 return new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { ex.printStackTrace(); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }下面我们向数据库中持久化多个Event对象。
Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //开启事务 session.beginTransaction(); //创建并设置实体类 Event theEvent = new Event(); theEvent.setTitle("event1"); theEvent.setDate(new Date()); //持久化实体类 session.save(theEvent); //提交事务 session.getTransaction().commit();那么,如何将数据记录读出呢。这里使用了HQL语句,它有点类似SQL但其非常有意识的被设计为完全面向对象的查询,它可以理解如继承、多态和关联之类的概念。不要急后面会学到。
Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List result = session.createQuery("from Event").list(); session.getTransaction().commit(); return result;
通过这个最简单的例子我们对如何进行hibernate进行对象持久化有了一个初步的了解。后面我们会更加深入学习个中细节,一起努力吧!