Hibernate是用来实现ORM的。应该说ORM一直是讨论得热火朝天的技术,因为实际开发中持久化方面的内容是相当重要的,所以ORM的实现也有很多。Hibernate之所以最被推崇,除开它的血统之外,灵活性也是一大原因。
ORM中的O-object,是指POJO,全称是Pure Old Java Object 或者 Plain Ordinary Java Object 或者 Pussy Of Jennifer Oasca,我的意思是它叫什么名字并不重要。之所以说它是纯的,是指它完全是一个数据对象的集合,没有含有任何与操作相关的代码。用new创建,由GC回收。
ORM中的R-relation,是指关系数据库中的表,在我的例子中就是MySQL数据库中的表,一个表就表示了一个关系。
ORM中的M-mapping files,是指我们的hbm文件和cfg文件。这些文件定义了OR之间的Mapping方式。
在使用Hibernate时,作为开发者,建立O、R、M三个部分的顺序是怎样的呢?实际上,ORM中任意得到一个,我们都可以生成其他两个。这就是Hibernate的灵活性的一个很好的体现。在下面的例子中,会针对三种不同的顺序来给出三个解决方案。这就是第一个Hibernae程序还有“之一”的原因。
首先按照数据库已经存在时的开发顺序:R-O-M
1.建立工程
new-project-Java project
工程名定为HibernateSample1_1,再点“next”
选择“Libraries”
选择“User Libraries”
选择“hibernate”,这个工程中我们要用到的自定义库,然后点“Finish”
这样,第一个项目就建立起来了。
2.根据现有的数据库编写POJO
假设现在在MySQL数据库中有叫做User_Table的表。当然这个需要我们去建立。
它的属性分别有:user_id,name,sex,age。 生成它的脚本如下:
| CREATE TABLE USER ( user_id CHAR(32) NOT NULL PRIMARY KEY, name VARCHAR(16) NOT NULL, sex CHAR(1), age INT ); |
那么我们编写的POJO为一个叫做User的类:
| package lenciel.hibernate.model public class User { private String id; private String name; private char sex; private int age; public int getAge() { return age; } public String getId() { return id; } public String getName() { return name; } public char getSex() { return sex; } public void setAge(int i) { age = i; } public void setId(String string) { id = string; } public void setName(String string) { name = string; } public void setSex(char c) { sex = c; } } |
这个类没有什么特别的地方,其中的id是我们需要注意的地方。Hibernate使用这个属性来进行主键识别,id的生成方式需要我们定义,可以看看这里。我们可以在匹配文件中进行这方面的定义,下面就是User类对应的XML格式的匹配文件User.hbm.xml
| <?xml version=”1.0″?> <!DOCTYPE hibernate-mapping PUBLIC “-//Hibernate/Hibernate Mapping DTD//EN” “http://hibernate.sourceforge.net/ hibernate-mapping-2.0.dtd”> <hibernate-mapping> <class name=” lenciel.hibernate.model.User” table=”USER”> <id name=”id” type=”string” unsaved-value=”null”> <column name=”user_id” sql-type=”char(32)” /> <generator class=”uuid.hex”/> </id> <property name=”name” type=”string” not-null=”true”> <column name=”name” length=”16″ not-null=”true”/> </property> <property name=”sex” type=”char”/> <property name=”age” type=”int”/> </class> </hibernate-mapping> |
我们看到,在class标签内,我们首先定义的是User这POJO类与数据库中的关系(二维表)的对应:
| <class name=” lenciel.hibernate.model.User” table=”USER”> |
接着是使用id标签对主键的生成方式和一系列的属性进行定义。
uuid.hex算法用的是IP地址,系统时间,JVM启动时间和一个计数值来生成主键。常用的还有increment等。一般在数据库中,都有辅助的主键生成方法,比如自增长字段等,因此Hibernate也允许使用“native”算法,也就是采用数据库自己的方式去生成和维护主键。但是由于这种方法在网络中有大量造成数据库insert操作的请求并发的时候并不太好(容易出现互锁),因此uuid.hex算法据说是最好的。当然,我们学习时,可以把Hibernate提供的算法都玩一玩。
unsaved-value也是id属性的定义中一个值得注意的地方。这个值用来为Hibernate的非显式保存服务。这个后面会仔细分析到。简单的说,在程序中调用save(),update()等方法的时候,就显式的保存了数据。而在有的情况下,典型的比如级联的情况,在关系中一方做了保存,级联的另一方也保存,这个时候的保存就是隐式的。Hibernate通过unsaved-value这个属性值来判断对象是否进行了保存。
<property>标签用来定义POJO中的一般属性。当中的<column>标签用来定义和数据库的属性(列)的对应。对于我们手动生成POJO和数据库的情况而言,可以只定义<property name=”sex”/>,其他的属性主要是用来和我们后面要讲到的一些自动生成工具配合的。
接下來我们定义Hibernate配置文件,主要是进行SessionFactory配置,Hibernate可以使用XML或属性文件來进行配置,其中XML比较灵活清晰,也是Hibernate推荐的配置方式,具体如下:
| <?xml version=’1.0′ encoding=’GBK’?> <!DOCTYPE hibernate-configuration PUBLIC “-//Hibernate/Hibernate Configuration DTD//EN” ”http://hibernate.sourceforge.net/ hibernate-configuration-2.0.dtd”> <hibernate-configuration> <session-factory> <!– 是否将运行期生成的SQL输出到日志以供调试 –> <property name=”show_sql”>true</property> <!– SQL方言,这里设定的是MySQL –> <property name=”dialect”> net.sf.hibernate.dialect.MySQLDialect </property> <!– JDBC驱动程序 –> <property name=”connection.driver_class”> com.mysql.jdbc.Driver </property> <!– JDBC URL, “?useUnicode=true&characterEncoding=GBK” 表示使用GBK进行编码 –> <property name=”connection.url”> jdbc:mysql://localhost:3306/HibernateTest? useUnicode=true&characterEncoding=GBK </property> <!– 数据库用户名 –> <property name=”connection.username”>root</property> <!– 数据库密码 –> <property name=”connection.password”>pft</property> <!– 指定User的映射文件 –> <mapping resource=”lenciel/hibernate/model/User.hbm.xml”/> </session-factory> </hibernate-configuration> |
接下来我们写一个Test类。你可以看到,Hibernate帮助我们使用Java编程中熟悉的面向对象的方式来处理数据库中的数据:
| import net.sf.hibernate.*; import net.sf.hibernate.cfg.*; public class Test { public static void main(String[] args) throws HibernateException { SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); User user = new User(); user.setName(“lenciel”); user.setSex(‘M’); user.setAge(23); Session session = sessionFactory.openSession(); Transaction tx= session.beginTransaction(); session.save(user); tx.commit(); session.close(); sessionFactory.close(); System.out.println(“第一次操作完成了!”); } } |
打开MySQL Browser我们可以就可以看到数据库中多了一条记录了。下面先说一下Test中展现的Hibernate的一些核心接口。
Configuration
它负责管理Hibernate的配置信息,主要是面向数据库的一些底层实现的基本信息:
URL
用户
密码
JDBC驱动类
方言dialect
我们必须在配置文件(hibernate.cfg.xml或者hibernate.properties)中定义好这些信息,当程序运行到:
| SessionFactory sessionFactory = new Configuration().configure()… |
Hibernate会自动在当前的CLASSPATH中搜索配置文件,完成基础配置。然后这个类一般会被用来生成SessionFactory,之后就无用了。
SessionFactory
它负责建立Session实例。如前面所说,我们可以通过Configuration来构建SessionFactory:
| SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); |
SessionFactory一旦构建完毕,就有了自己的配置信息。这时再变动config不会影响到它的实例。如果确实需要改变的话只能重新建立。SessionFactory一般就是对应一个对数据库的,我们的程序中有一个数据库的话,一般只要一个SessionFactory就可以了。
Session
Session是Hibernate中我们大量操作的东西,因为实际上它就对应JDBC中的Connection。我们可以通过对它的save、update、load等方法完成对数据库的操作。
Transaction
一个Transaction就是一个事务,这个概念在数据库中是比较基础的。我们对数据库的要求有ACID指标,其中A代表原子性。原子性是指:一组对数据库的操作要么全部发生,要么全部不发生。这个和网络传输中的报文完整性要求比较像。
要保证原子性,我们定义数据库操作必须是以Transaction也就是事务为单位的:一个事务就是一组操作的集合,它的结果只有两种,要么是正常提交(commit),要么是出错回滚(rollback)。
MySQL好像比较新的版本才刚刚支持事务的概念。


No comments
Jump to comment form | comments rss [?] | trackback uri [?]