??xml version="1.0" encoding="utf-8" standalone="yes"?> 使用Hibernate自带的工?em>hbm2ddlQ徏立根据你的对象徏立数据库: 首先建好POJO object, XML Mapping File(也可以用工h据POJO class建立)Q配|文?hibernate.cfg.xml) Java代码
最q看<<深入出Hibernate>>,作者在书中介绍?span class="hilite1">Hibernate 提供的用戯定义数据cdQ于是效仿书中的ҎQ在数据库表中添加一个字D는于记录所有好友的useridQ每个userid之间?;"加以分隔Q同时将该字D|ؓ一个特D的List集合Q利用UserType interface实现String解析后将各个userid装在List中,List中的记录装成以";"分隔的String?
使用UserType接口Q实C较好的设计风|以及更好的重用性?
/*
* 用户自定义的数据cdQ对应数据库中的一个字D,在该字段中,保存?
* 多个用户需要的信息Q之间用";"加以分隔.
* @Author:Paul
* @Date:April 18th,2008
*/
package com.globalhands.hibernate.userTypes;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Types;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class SpecialList implements UserType {
private List specialList;
private static final char SPLITTER = ';';
private static final int[] TYPES = new int[] { Types.VARCHAR };
public String assemble(Serializable arg0, Object arg1)
throws HibernateException {
return null;
}
/*
* List装Z个String对象
*/
public String assemble(List specialList) throws HibernateException {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < specialList.size() - 1; i++) {
sb.append(specialList.get(i)).append(this.SPLITTER);
}
sb.append(specialList.get(specialList.size() - 1));
return sb.toString();
}
/*
* 创徏一个新的List实例Q包含原有的List实例中的所有元?
*/
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List) value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}
public Serializable disassemble(Object arg0) throws HibernateException {
return null;
}
/*
* 判断specialList是否发生变化
*/
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (x != null && y != null) {
List xList = (List) x;
List yList = (List) y;
if (xList.size() != yList.size()) {
return false;
}
for (int i = 0; i <= xList.size() - 1; i++) {
String str1 = (String) xList.get(i);
String str2 = (String) yList.get(i);
if (!xList.equals(yList)) {
return false;
}
}
return true;
}
return false;
}
public int hashCode(Object arg0) throws HibernateException {
return 0;
}
public boolean isMutable() {
return false;
}
/*
* 从resultset中取出email字段Qƈ其解析为Listcd后返?
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
if (value != null) {
return parse(value);
} else {
return null;
}
}
/*
* 以";"分隔的字W串解析Z个字W串数组
*/
private List parse(String value) {
String[] strs = value.split(";");
List specialList = new ArrayList();
for (int i = 0; i <= strs.length - 1; i++) {
specialList.add(strs[i]);
}
return specialList;
}
/*
* List型的email信息l装成字W串之后保存到email字段
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
String str = assemble((List) value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
return null;
}
public Class returnedClass() {
return List.class;
}
public int[] sqlTypes() {
return TYPES;
}
}
同时Q修改相应的[ormapping_filename].hbm.xml中相应字D늚映射信息
<property name="buddy" type="com.globalhands.hibernate.userTypes.SpecialList">
<column name="buddy" length="2000" not-null="true" />
</property>
之后Q修改POJOcM该字D늚q回cd为List?
使用JUnit试E序?
即通常所说的“悲观锁(Pessimistic LockingQ?#8221;?
“乐观锁(OptimisticLockingQ?#8221;?
悲观锁的实现Q往往依靠数据库提供的锁机Ӟ也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则Q即使在本系l中实现了加锁机Ӟ也无法保证外部系l不会修Ҏ据)?
Hibernate的加锁模式有Q?
Ø LockMode.NONE Q?无锁机制?
Ø LockMode.WRITE Q?span class="hilite1">Hibernate在Insert和Update记录的时候会自动
获取?
Ø LockMode.READ Q?Hibernate在读取记录的时候会自动获取?
以上q三U锁机制一般由Hibernate内部使用Q如HibernateZ保证Update
q程中对象不会被外界修改Q会在saveҎ实现中自动ؓ目标对象加上WRITE锁?
Ø LockMode.UPGRADE Q利用数据库的for update子句加锁?
Ø LockMode. UPGRADE_NOWAIT QOracle的特定实玎ͼ利用Oracle的for
update nowait子句实现加锁?
乐观锁,大多是基于数据版本(VersionQ记录机制实现。何谓数据版本?即ؓ数据增加一个版本标识,在基于数据库表的版本解决Ҏ中,一般是通过为数据库表增加一?#8220;version”字段来实现。读取出数据Ӟ此版本号一同读出,之后更新ӞҎ版本号加一。此Ӟ提交数据的版本数据与数据库表对应记录的当前版本信息q行比对Q如果提交的数据版本号大于数据库表当前版本号Q则予以更新Q否则认为是q期数据?
悲观锁与乐观锁的比较:
悲观锁大多数情况下依靠数据库的锁机制实现Q以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销Q特别是寚w事务而言Q这L开销往往无法承受;
相对悲观锁而言Q乐观锁机制采取了更加宽杄加锁机制。乐观锁机制往往Zpȝ中的数据存储逻辑Q因此也具备一定的局限性,如在上例中,׃乐观锁机制是在我们的pȝ中实玎ͼ来自外部pȝ的更新操作不受我们系l的控制Q因此可能会造成脏数据被更新到数据库中。在
pȝ设计阶段Q我们应该充分考虑到这些情况出现的可能性,q进行相应调_如将乐观锁策略在数据库存储过E中实现Q对外只开攑֟于此存储q程的数据更新途径Q而不是将数据库表直接对外公开Q?
Hibernate 在其数据讉K引擎中内|了乐观锁实现。如果不用考虑外部pȝҎ据库的更新操作,利用Hibernate提供的透明化乐观锁实现Q将大大提升我们的生产力?
Hibernate中可以通过class描述W的optimistic-lock属性结合version描述W指定?
optimistic-lock属性有如下可选取|
Ø none
无乐观锁
Ø version
通过版本机制实现乐观?
Ø dirty
通过查发生变动过的属性实C观锁
Ø all
通过查所有属性实C观锁
其中通过version实现的乐观锁机制?span class="hilite1">Hibernate官方推荐的乐观锁实现Q同时也?span class="hilite1">Hibernate中,目前唯一在数据对象脱?Session发生修改的情况下依然有效的锁机制。因此,一般情况下Q我们都选择version方式作ؓHibernate乐观锁实现机制?
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class SchemaUtil {
public static void main(String[] args) {
Configuration cfg = new Configuration().configure();
SchemaExport schemaExport= new SchemaExport(cfg);
schemaExport.create(false, true);
}
}
<?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="onlyfun.caterpillar.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>
在這個映文件中Q?lt;column/>標籤用於指定建立表格時的一些資a,例如映射的表格欄位名E,或是sql-type?length{屬性,如果不指定這些資訊時,SchemaExportTask自動用Hibernate的類型至SQL型{資a來建立表格Qsql -type用於指定表格Ƅ位型態Qnot-null表示Ƅ位不能為nullQlength則用於指定表格文字欄位長度,這些屬性的說明Q都可以?Hibernate參考手冊的?5.1扑ֈ?/p>
下面的build.xml用於Ant自動化徏構時Q生成資料n表格之用Q?/p>
<project name="Hibernate" default="schema" basedir="."> <property name="source.root" value="src"/> <property name="class.root" value="classes"/> <property name="lib.dir" value="lib"/> <property name="data.dir" value="data"/> <path id="project.class.path"> <!-- Include our own classes, of course --> <pathelement location="${class.root}" /> <!-- Include jars in the project library directory --> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> <pathelement path ="${classpath}"/> </path> <target name="schema" description="Generate DB schema from the O/R mapping files"> <!-- Teach Ant how to use Hibernate's schema generation tool --> <taskdef name="schemaexport" classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="project.class.path"/> <schemaexport properties="${source.root}/hibernate.properties" quiet="no" text="no" drop="no" delimiter=";"> <fileset dir="${source.root}"> <include name="**/*.hbm.xml"/> </fileset> </schemaexport> </target> </project>
<taskdef/>標籤定義一個新的Q務schemaexportQ相關的屬性設定是Ҏ參考手冊的a定的,我們在這邊使用 hibernate.properties來告aSchemaExportTask盔R的JDBC資訊Qquiet、text{屬性的定義Q可以看參考手冊的?5.2?/p>
這個Ant建構檔案Q會扑ְsrc目錄下包括子目錄中有?.hbm.xmlQ並自動Ҏ映射資訊建立表格Q我們還必須提供hibernate.propertiesQ置於src下)來告知JDBC連接的相關訊息:
hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost/HibernateTest
hibernate.connection.username=caterpillar
hibernate.connection.password=123456
這邊使用的是MySQLQ請實際Ҏ您所使用的資料na定dialect、驅動程式等資訊Q在開始運行Ant使用SchemaExportTask進行自動表格建立之前Q您要先建立資料庫,這邊的例子則是在MySQL中先建立HibernateTestQ?/p>
mysql> create database HibernateTest; Query OK, 1 row affected (0.03 sec)
接著可以運行Ant了,埯i果如下Q?/p>
ant Buildfile: build.xml schema: [schemaexport] log4j:WARN No appenders could be found for logger (net.sf.hiberna te.cfg.Environment). [schemaexport] log4j:WARN Please initialize the log4j system properly. [schemaexport] drop table if exists USER; [schemaexport] create table USER ( [schemaexport] user_id char(32) not null, [schemaexport] name varchar(16) not null, [schemaexport] sex char(1), [schemaexport] age integer, [schemaexport] primary key (user_id) [schemaexport] ); BUILD SUCCESSFUL Total time: 5 seconds
運行的過E中Q我們可以看到徏立表格的SQL語句Q而自動徏立好的資料n表格資訊如下Q?/p>
mysql> DESCRIBE user; +---------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+-------+ | user_id | varchar(32) | | PRI | | | | name | varchar(16) | | | | | | sex | char(1) | YES | | NULL | | | age | int(11) | YES | | NULL | | +---------+-------------+------+-----+---------+-------+ 4 rows in set (0.04 sec)
更多有關SchemaExportTask的資a,可以看看參考手冊的W?5章工L指南的部份?/p>
Hibernate 的缓存体p?br />
一U缓存:
Session 有一个内|的~存Q其中存放了被当前工作单元加载的对象?br />
每个Session 都有自己独立的缓存,且只能被当前工作单元讉K?br />
二~存Q?br />
SessionFactory的外|的可插拔的~存插g。其中的数据可被多个Session׃n讉K?br />
SessionFactory的内|缓存:存放了映元数据Q预定义的Sql语句?/p>
Hibernate 中Java对象的状?br />
1.临时状?(transient)
特征Q?br />
1】不处于Session ~存?br />
2】数据库中没有对象记?br />
Java如何q入临时状?br />
1】通过new语句刚创Z个对象时
2】当调用Session 的delete()ҎQ从Session ~存中删除一个对象时?/p>
2.持久化状?persisted)
特征Q?br />
1】处于Session ~存?br />
2】持久化对象数据库中设有对象记录
3】Session 在特定时M保持二者同?br />
Java如何q入持久化状?br />
1】Session 的save()把Ӟ》持久化状?br />
2】Session 的load(),get()Ҏq回的对?br />
3】Session 的find()q回的list集合中存攄对象
4】Session 的update(),saveOrupdate()使游-》持久化
3.游离状?detached)
特征Q?br />
1】不再位于Session ~存?br />
2】游d象由持久化状态{变而来Q数据库中可能还有对应记录?br />
Java如何q入持久化状态-》游ȝ?br />
1】Session 的close()Ҏ
2】Session 的evict()ҎQ从~存中删除一个对象。提高性能。少用?/p>
“Hello World”“Hello world”CZE序让您对Hibernate有一个简单的认识?
理解Hibernate的架构介lHibernate接口的主要功能?
核心接口Hibernate?个核心接口,通过q几个接口开发h员可以存储和获得持久对象Qƈ且能够进行事务控?
一个重要的术语QTypeType是Hibernate发明者发明的一个术语,它在整个构架中是一个非常基、有着强大功能的元素,一个Type对象能将一个Javacd映射到数据库中一个表的字D中厅R?
{略接口Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现?
基础配置Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端?
创徏一个SessionFactory对象要创Z个SessionFactory对象Q必dHibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理?
“Hello World”
Hibernate应用E序定义了一些持久类Qƈ且定义了q些cM数据库表格的映射关系。在我们q个“Hello world”CZE序中包含了一个类和一个映文件。让我们看看q个单的持久cd含有一些什么?映射文g是怎样定义的?另外Q我们该怎样用Hibernate来操作这个持久类?
我们q个单示例程序的目的是将一些持久类存储在数据库中,然后从数据库取出来,q将其信息正文显C给用户。其中Message正是一个简单的持久c:Q它包含我们要显C的信息Q其源代码如下:
列表1 Message.Java 一个简单的持久c?
package hello;
public class Message {
private Long id;
private String text;
private Message nextMessage;
private Message() {}
public Message(String text) {
this.text = text;
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Message getNextMessage() {
return nextMessage;
}
public void setNextMessage(Message nextMessage) {
this.nextMessage = nextMessage;
}
}
MessagecL三个属性:Message的id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息,通常它等同于数据库中的主键,如果多个Messagecȝ实例对象拥有相同的idQ那它们代表数据库某个表的同一个记录。在q里我们选择了长整型作ؓ我们的id|但这不是必需的。Hibernate允许我们使用L的类型来作ؓ对象的id|在后面我们会Ҏ作详l描q?
你可能注意到Messagecȝ代码cM于JavaBean的代码风|q且它有一个没有参数的构造函敎ͼ在我们以后的代码中我l用这U风格来~写持久cȝ代码?
Hibernate会自动管理Messagecȝ实例Qƈ通过内部机制使其持久化,但实际上Message对象q没有实CQ何关于Hibernate的类或接口,因此我们也可以将它作Z个普通的JavacL使用Q?
Message message = new Message("Hello World");
System.out.println( message.getText() );
以上q段代码正是我们所期望的结果:它打?#8220;hello world”到屏q上。但qƈ不是我们的最l目标;实际上Hibernate与诸如EJB容器q样的环境在持久层实现的方式上有很大的不同。我们的持久c?Messagec?可以用在与容器无关的环境中,不像EJB必须要有EJB容器才能执行。ؓ了能更清楚地表现q点Q以下代码将我们的一个新消息保存到数据库中去Q?
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Message message = new Message("Hello World");
session.save(message);
tx.commit();
session.close();
以上q段代码调用了Hibernate的Session和Transaction接口Q关于getSessionFactory()Ҏ我们会马上提到Q。它相当于我们执行了以下SQL语句Q?
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (1, 'Hello World', null)
在以上的SQL语句中,MESSAGE_ID字段到底被初始化成了什么值呢Q由于我们ƈ没有在先前的代码中ؓmessage对象的id属性赋与初始|那它是否为null呢?实际上Hibernate对id属性作了特D处理:׃它是一个对象的唯一标识Q因此当我们q行save()调用ӞHibernate会ؓ它自动赋予一个唯一的|我们在后面内容中讲q它是如何生成这个值的Q?
我们假设你已l在数据库中创徏了一个名为MESSAGE的表Q那么既然前面这D代码让我们Message对象存入了数据库中,那么现在我们p它们一一取出来。下面这D代码将按照字母序Q将数据库中的所有Message对象取出来,q将它们的消息正文打印到屏幕上:
Session newSession = getSessionFactory().openSession();
Transaction newTransaction = newSession.beginTransaction();
List messages =newSession.find("from Message as m order by m.text asc");
System.out.println( messages.size() + " message(s) found:" );
for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {
Message message = (Message) iter.next();
System.out.println( message.getText() );
}
newTransaction.commit();
newSession.close();
在以上这D代码中Q你可能被find()Ҏ的这个参数困扰着Q?from Message as m order by m.text asc"Q其实它是Hibernate自己定义的查询语aQ全U叫Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关pd不多是方言与普通话之间的关p,咋一看,你会觉得它有点类gSQL语句。其实在find()调用ӞHibernate会将q段HQL语言译成如下的SQL语句Q?
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
order by m.MESSAGE_TEXT asc
以下是q行l果Q?
1 message(s) found:
Hello World
如果你以前没有ORMQ对象-关系映射Q的开发经验,那你可能惛_代码的某个地方去Lq段SQL语句Q但在Hibernate中你可能会失望:它根本不存在Q所有就SQL语句都是Hibernate动态生成的?
也许你会觉得q缺点什么,对!仅凭以上代码Hibernate是无法将我们的MessagecL久化的。我们还需要一些更多的信息Q这是映射定义表!q个表在Hibernate中是以XML格式来体现的Q它定义了Messagecȝ属性是怎样与数据库中的MESSAGES表的字段q行一一对应的,列表2是这个示例程序的映射配置文g清单Q?
列表2Q示例程序的对象Q关pL表
Q?xml version="1.0"?Q?
Q?DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"Q?
Qhibernate-mappingQ?
Qclass name="hello.Message" table="MESSAGES"Q?
Qid name="id" column="MESSAGE_ID"Q?
Qgenerator class="increment"/Q?
Q?idQ?
Qproperty name="text" column="MESSAGE_TEXT"/Q?
Qmany-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/Q?
Q?classQ?
Q?hibernate-mappingQ?
以上q个文档告诉Hibernate怎样MessagecL到MESSAGES表中Q其中Messagecȝid属性与表的MESSAGE_ID字段对应Qtext属性与表的MESSAGE_TEXT字段对应QnextMessage属性是一个多对一的关p,它与表中的NEXT_MESSAGE_ID相对应?
相对于有些开源项目来_Hibernate的配|文件其实是很容易理解的。你可以LC改与l护它。只要你定义好了持久cM数据库中表字D늚对应关系p了,Hibernate会自动帮你生成SQL语句来对Message对象q行插入、更新、删除、查扑ַ作,你可以不写一句SQL语句Q甚至不需要懂得SQL语言Q?
现在让我们做一个新的试验,我们先取出第一个Message对象Q然后修改它的消息正文,最后我们再生成一个新的Message对象Qƈ它作ؓW一个Message对象的下一条消息,其代码如下:
列表3 更新一条消?
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
// 1 is the generated id of the first message
Message message =(Message) session.load( Message.class, new Long(1) );
message.setText("Greetings Earthling");
Message nextMessage = new Message("Take me to your leader (please)");
message.setNextMessage( nextMessage );
tx.commit();
session.close();
以上q段代码在调用时QHibernate内部自动生成如下的SQL语句Q?
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
where m.MESSAGE_ID = 1
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (2, 'Take me to your leader (please)', null)
update MESSAGES
set MESSAGE_TEXT = 'Greetings Earthling', NEXT_MESSAGE_ID = 2
where MESSAGE_ID = 1
当第一个Message对象的text属性和nextMessage被程序修ҎQ请注意Hibernate是如何检到q种变化Qƈ如何在数据库中自动对它更新的。这实际上是Hibernate的一个很有h值的特色Q我们把它称?#8220;自动脏数据检?#8221;QHibernate的这个特色得当我们修改一个持久对象的属性后Q不必显式地通知Hibernated它在数据库中q行更新。同LQ当W一个Message对象调用setNextMessage()Ҏ第二个Message对象作ؓ它的下一条消息的引用ӞW二条消息会无需调用save()ҎQ便可以自动C存在数据库中。这U特色被UCؓ“U联保存”Q它也免M我们昑ּ地对W二个Message对象调用save()Ҏ之苦?
如果我们再运行先前的那段数据库中所有的Message对象都打印出来的代码Q那它的q行l果如下Q?
2 message(s) found:
Greetings Earthling
Take me to your leader (please)
“Hello world”CZE序现在介绍完毕。我们ȝ对Hibernate有了一个简单的认识Q下面我们将回过头来Q对Hibernate的主要API调用作一下简要的介绍Q?
理解Hibernate的架?/strong>
当你想用Hibernate开发自qZ持久层的应用ӞW一件事情应当是熟悉它的~程接口。Hibernate的API接口设计得尽量简z明了,以方便开发h员。然而实际上׃ORM的复杂性,它的API一般都不可能设计得很简单。但是别担心Q你没有必要一下子了解所有的Hibernate的API接口?br />
我们应用层攑֜了持久层的上部,实际上在传统的项目中Q应用层充当着持久层的一个客L角色。但对于一些简单的目来说Q应用层和持久层q没有区分得那么清楚Q这也没什么,在这U情况下你可以将应用层和持久层合q成了一层?
Hibernate的接口大致可以分Z下几U类型:
· 一些被用户的应用程序调用的Q用来完成基本的创徏、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户E序的商业逻辑的主要接口,它们包括Session、Transaction和Query?
· Hibernate用来d诸如映射表这c配|文件的接口Q典型的代表有ConfigurationcR?
· 回调(Callback)接口。它允许应用E序能对一些事件的发生作出相应的操作,例如Interceptor、Lifecycle和Validatable都是q一cL口?
· 一些可以用来扩展Hibernate的映机制的接口Q例如UserType、CompositeUserType和IdentifierGenerator。这些接口可qL序来实现Q如果有必要Q?
Hibernate使用了J2EE架构中的如下技术:JDBC、JTA、JNDI。其中JDBC是一个支持关pL据库操作的一个基层;它与JNDI和JTA一L合,使得Hibernate可以方便地集成到J2EE应用服务器中厅R?
在这里,我们不会详细地去讨论Hibernate API接口中的所有方法,我们只简要讲一下每个主要接口的功能Q如果你想了解得更多的话Q你可以在Hibernate的源码包中的net.sf.hibernate子包中去查看q些接口的源代码。下面我们依ơ讲一下所有的主要接口Q?
核心接口
以下5个核心接口几乎在M实际开发中都会用到。通过q些接口Q你不仅可以存储和获得持久对象,q且能够q行事务控制?
Session接口
Session接口对于Hibernate 开发h员来说是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量的类Q创建和销毁它都不会占用很多资源。这在实际项目中实很重要,因ؓ在客L序中Q可能会不断地创Z及销毁Session对象Q如果Session的开销太大Q会l系l带来不良媄响。但值得注意的是Session对象是非U程安全的,因此在你的设计中Q最好是一个线E只创徏一个Session对象?
在Hibernate的设计者的头脑中,他们session看作介于数据q接与事务管理一U中间接口。我们可以将session惌成一个持久对象的~冲区,Hibernate能检到q些持久对象的改变,q及时刷新数据库。我们有时也USession是一个持久层理器,因ؓ它包含这一些持久层相关的操作,诸如存储持久对象x据库Q以及从数据库从获得它们。请注意QHibernate 的session不同于JSP应用中的HttpSession。当我们使用sessionq个术语Ӟ我们指的是Hibernate中的sessionQ而我们以后会HttpSesion对象UCؓ用户session?
SessionFactory 接口
q里用到了一个设计模式――工厂模式,用户E序从工厂类SessionFactory中取得Session的实例?
令你感到奇怪的是SessionFactoryq不是轻量的!实际上它的设计者的意图是让它能在整个应用中׃n。典型地来说Q一个项目通常只需要一个SessionFactory够了,但是当你的项目要操作多个数据库时Q那你必Mؓ每个数据库指定一个SessionFactory?
SessionFactory在Hibernate中实际vC一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据Q还~冲了一些将来有可能重复利用的数据?
Configuration 接口
Configuration接口的作用是对Hibernateq行配置Q以及对它进行启动。在Hibernate的启动过E中QConfigurationcȝ实例首先定位映射文档的位|,dq些配置Q然后创Z个SessionFactory对象?
虽然Configuration接口在整个Hibernate目中只扮演着一个很的角色Q但它是启动hibernate时你所遇到的每一个对象?
Transaction 接口
Transaction接口是一个可选的APIQ你可以选择不用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码?Transaction接口是对实际事务实现的一个抽象,q些实现包括JDBC的事务、JTA中的UserTransaction、甚臛_以是CORBA事务。之所以这栯计是能让开发者能够用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移倹{?
Query和Criteria接口
Query接口让你方便地对数据库及持久对象q行查询Q它可以有两U表达方式:HQL语言或本地数据库的SQL语句。Queryl常被用来绑定查询参数、限制查询记录数量,q最l执行查询操作?
Criteria接口与Query接口非常cMQ它允许你创建ƈ执行面向对象的标准化查询?
值得注意的是Query接口也是轻量U的Q它不能在Session之外使用?
Callback 接口
当一些有用的事g发生时――例如持久对象的载入、存储、删除时QCallback接口会通知HibernateL收一个通知消息。一般而言QCallback接口在用L序中q不是必ȝQ但你要在你的项目中创徏审计日志Ӟ你可能会用到它?
一个重要的术语QType
Hibernate的设计者们发明了一个术语:TypeQ它在整个构架中是一个非常基、有着强大功能的元素。一个Type对象能将一个Javacd映射到数据库中一个表的字D中去(实际上,它可以映到表的多个字段中去Q。持久类的所有属性都对应一个type。这U设计思想使用Hibernate有着高度的灵zL和扩展性?
Hibernate内置很多typecdQ几乎包括所有的Java基本cdQ例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable?
不仅如此QHibernateq支持用戯定义的typeQ通过实现接口UserType和接口CompositeUserTypeQ你可以加入自己的type。你可以利用q种特色让你的项目中使用自定义的诸如Address、Nameq样的typeQ这样你可以获得更大的便利Q让你的代码更优雅。自定义type在Hibernate中是一Ҏ心特Ԍ它的设计者鼓׃多多使用它来创徏一个灵zR优雅的目Q?
{略接口
Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现。当你感觉到Hibernate的某些功能不I或者有某些~陷Ӟ你可以开发一个自q{略来替换它Q而你所要做的仅仅只是承它的某个策略接口,然后实现你的新策略就可以了,以下是它的策略接口:
· 主键的生?(IdentifierGenerator 接口)
· 本地SQL语言支持 (Dialect 抽象c?
· ~冲机制 (Cache 和CacheProvider 接口)
· JDBC q接理 (ConnectionProvider接口)
· 事务理 (TransactionFactory, Transaction, ?TransactionManagerLookup 接口)
· ORM {略 (ClassPersister 接口)
· 属性访问策?(PropertyAccessor 接口)
· 代理对象的创?(ProxyFactory接口)
HibernateZ上所列的机制分别创徏了一个缺省的实现Q因此如果你只是要增强它的某个策略的功能的话Q只需单地l承q个cd可以了,没有必要从头开始写代码?
以上是Hibernate的一些核心接口,但当我们真正开始用它进行开发时Q你的脑里可能M有一个疑问:我是通过什么方式,q从哪里取得Session的呢Q以下我们就解答q个问题?
基础配置
现在回顾一下我们先前的内容Q我们写Z一个示例程序,q简要地讲解了Hibernate的一些核心类。但要真正你的目q行hQ还有一件事必须要做Q配|。Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端。在q种目中,Web览器、或Java GUIE序充当者客L。尽我们的焦点主要是集中在多层web应用Q但实际上在一些基于命令行的应用中也可以用Hibernate。ƈ且,对Hibernate的配|在不同的环境下都会不同QHibernateq行在两U环境下Q可理环境和不可管理环?
· 可管理环境――这U环境可理如下资源Q池资源理Q诸如数据库q接池和Q还有事务管理、安全定义。一些典型的J2EE服务器(JBoss、Weblogic、WebSphereQ已l实Cq些?
· 不可理环境――只是提供了一些基本的功能Q诸如像Jetty或Tomcatq样的servlet容器环境。一个普通的Java桌面应用或命令行E序也可以认为是处于q种环境下。这U环境不能提供自动事务处理、资源管理或安全理Q这些都必须由应用程序自己来定义?
Hibernate的设计者们这两种环境设计了一个统一的抽象界面,因此对于开发者来说只有一U环境:可管理环境。如果实际项目是建立在诸如Tomcatq类不可理的环境中Ӟ那Hibernate会使用它自q事务处理代码和JDBCq接池,使其变ؓ一个可理环境?
对于可管理的环境而言QHibernate会将自己集成在这U环境中。对于开发者而言Q你所要做的工作非常简单:只需从一个ConfigurationcM创徏一个SessionFactorycd可以了?
创徏一个SessionFactory对象
Z能创Z个SessionFactory对象Q你必须在Hibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理。这PConfiguration对象可以创Z个SessionFactory对象Q当SessionFactory对象创徏成功后,Configuration对象没有用了,你可以简单地抛弃它。如下是CZ代码Q?
Configuration cfg = new Configuration();
cfg.addResource("hello/Message.hbm.xml");
cfg.setProperties( System.getProperties() );
SessionFactory sessions = cfg.buildSessionFactory();
在以上代码中QMessage.hb.xmlq个映射文g的位|比较特D,它与当前的classpath相关。例如classpath包含当前目录Q那在上qC码中的Message.hbm.xml映射文g可以保存在当前目录下的hello目录中?
作ؓ一U约定,Hibernate的映文仉认以.htm.xml作ؓ其扩展名。另一个约定是坚持为每一个持久类写一个配|文Ӟ想一惛_果你所有持久类的映写入一个单独的配置文g中的话,那这个配|文件肯定非常庞大,不易l护。但q里又出C一个新问题Q如果ؓ每个cd一个配|文件的话,q么多的配置文g应该存放在哪里呢Q?
Hibernate推荐你将每个映射文g保存在与持久cȝ同的目录下,q且与持久类同名。例如我们第一个示例程序中的Message持久cL在hello目录下,那你必须在这个目录下存放名ؓMessage.hbm.xml的映文件。这样一个持久类都有自己的一个映文Ӟ避免了出现像struts目中的“struts-config.xml地狱”的情c如果你不遵循这U规定,那你必须手动地用addResource()Ҏ一个个的映文件蝲入;但你如果遵@q种规定Q那你可以方便地用addClass()Ҏ同时持久类和它的映文件蝲入,以下是体现这U便利性的CZ代码Q?
SessionFactory sessions = new Configuration()
.addClass(org.hibernate.auction.model.Item.class)
.addClass(org.hibernate.auction.model.Category.class)
.addClass(org.hibernate.auction.model.Bid.class)
.setProperties( System.getProperties() )
.buildSessionFactory();
当然QHibernate的映文件还有很多其它的配置选项Q比如数据库q接的设定,或是能够改变Hibernateq行时行为的一些设定。所有的讄可能是非常庞杂的Q以让你喘不过气来Q但是不必担心,因ؓHibernate为绝大多数值都讑֮了一个合理缺省|你只需要修改这些配|文件中的极一部分倹{?
你可以通过以下几种方式来修改Hibernate的系l配|参敎ͼ
· 一个Java.util.Properties实例作ؓ参数传给ConfigurationcȝsetProperties()Ҏ?
· 在Hibernate启动时用Java –Dproperty=value的方式设|倹{?
· 在classpath可以扑ֈ的\径下创徏一个名为hibernate.properties的配|文件?
· 在classpath可以扑ֈ的\径下创徏一个名为hibernate.cfg.xml的文Ӟq在ӞpropertyQ标{中定义属性倹{?
以上是对Hibernate的一个大致介l,如果你想知道得更多,那本文还是远q不够的Q我陆l推出更多关于Hibernate的资料。但有一Ҏ毫无疑问的:它的是一个非怼U的持久层解决ҎQ?/p>