歡迎您光臨本站 註冊首頁

Java企業應用-Hibernate實戰全解

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

bromon原創 請尊重版權

  對象關係映射(Object Relative Mapping)簡稱ORM,是面向對象開發的一個熱點,用來解決JDBC開發中手動進行OR映射的繁雜與不便。EJB中的實體Bean在這個領域是很著名的——既因為它的先進而著名,也因為它的低效而著名。有過實體Bean開發經驗的人可能都會為實現遠程介面造成的效率低下而頭痛,在很多不大不小的項目中,使用實體Bean是否得不償失,爭論很大。一個輕量級的持久化方案也許能夠解決一些問題,Hibernate應此而生。

  Hibernate是一個中間層,它的目的是把資料庫中的關係通過一定的規則映射成為對象,讓Java開發人員不用太多的考慮底層資料庫的問題,只需要像通常情況下管理對象一樣的管理數據。在關係資料庫仍將持續佔據市場的情況下,它很可觀。在數據持久化領域,即便是輕量級的方案也會是複雜饒舌的,也許如同周杰倫的音樂一樣不知所云。在學習它之前,最好先回想一下以前進行資料庫開發中遇到的問題和不便,想想為什麼需要一個持久化層,才能知道很多操作的目的是什麼,以及為什麼要這麼干,在這個問題上我不想做更多的敘述,因為「長久以來……」這樣的句式通常long(不好意思,打不出來)長,會對我的鍵盤和熱情造成很大的磨損。如果讓我寫一本書,那麼我會樂意去敘述什麼是數據持久化,它有什麼好處等等。廢話少說,來了。

  首先需要配置環境,下載Hibernate 2.1(www.hibernate.org),把lib下的*.jar添加到classpath,你的資料庫JDBC驅動程序也應該在classpath中。打開hibernate.properties,針對你使用的資料庫,配置相應的信息,比如我使用的是MS SQL Server,配置如下:

## MS SQL Server

hibernate.dialect net.sf.hibernate.dialect.SQLServerDialect
hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver
hibernate.connection.url jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=zizz
hibernate.connection.username sa
hibernate.connection.password

  其中很大部分是已經寫好的,只需要取掉註釋即可,我自己只是修改了資料庫名稱、帳號、密碼。建立一個名為zizz的資料庫備用。

  然後把這個文件拷貝到你的應用的根目錄下。

  我們談論了很多次映射,應該首先來看看這個映射是如何完成的。假設一個最簡單的應用,寫一個功能最單一的留言板,設計的數據有留言的編號、留言者名稱、留言內容,還有留言時間。足夠簡單吧,換做是你打算怎麼干?我猜你要首先建立一個資料庫表格,名字也許叫做guestbook。No,這不是面向對象的方式,不妨首先從對象的角度來考慮。我們當然希望每一條留言都以對象的方式呈現,每個對象應該具有的屬性有:id、author、content、time。偷個懶,沒有畫UML。下面這個類應該是很容易理解的:

//GuestBook.java
package org.bromon.zizz;

import java.util.*;

public class GuestBook
{
private int id;
private String author;
private String content;
private Calendar time;

private void setId(int id)
{
this.id=id;
}
public int getId()
{
return(id);
}

public void setAuthor(String author)
{
this.author=author;
}
public String getAuthro()
{
return(author);
}

public void setContent(String content)
{
this.content=content;
}
public String getContent()
{
return(content);
}

public void setTime(Calendar time)
{
this.time=time;
}
public Calendar getTime()
{
return(time);
}
}


  基本上是最簡單的Bean了,如果覺得困難的話,請你先回火星等我。

  需要注意的是setId方法被指定為private,這是因為我希望用這個欄位做主鍵,它最好由系統自動生成,所以不應該由用戶來指定,這個方法專為Hibernate準備,所以是私有的。

  如何把這個類與資料庫映射起來?看看Hibernate的魔法,使用一個XML文件來描述,它應該被命名為GuestBook.hbm.xml:

< ?xml version="1.0"? >
< !DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

< hibernate-mapping package="org.bromon.zizz" >
< class name="GuestBook" table=」guestbook" lazy="true" >
< id name="id" type="integer" unsaved-value="null" >
< column name="id" sql-type="int" not-null="true"/ >
< generator class="identity"/ >
< /id >

< property name="author" column="author" not-null="true" unique="false"/ >
< property name="content" column="content" not-null="true"/ >
< property name="time" column="time" not-null="true"/ >
< /class >
< /hibernate-mapping >

雖然有點陌生,但是很易讀,仔細琢磨一下。

下面來編寫我們的應用,它的功能是插入數據:

//Operate.java
package org.bromon.zizz;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import net.sf.hibernate.tool.hbm2ddl.*;
import java.util.*;

public class Operate
{
public static void main(String args[])
{
try
{
Configuration cfg=new Configuration().addClass(GuestBook.class);
SessionFactory sessions=cfg.buildSessionFactory();
new SchemaExport(cfg).create(true,true);
Session session=sessions.openSession();

GuestBook gb=new GuestBook();
gb.setAuthor(「Bromon」);
gb.setContent(「留言的內容」);
gb.setTime(Calendar.getInstance());

Transaction ts=session.beginTransaction();
session.save(gb);
ts.commit();
session.close();
}catch(Exception e)
{
System.out.println(e);
}
}
}
  編譯吧:javac ?d . *.java
  執行一下:java org.bromon.zizz.Operate

到資料庫裡面看看,表格已經建立好了,並且數據也已經保存。如果把

new SchemaExport().create(true,true);

註釋掉,那麼系統不會創建表格,而只是在已有的表格中添加新的記錄,當然,如果表格不存在的話,會產生異常。

你已經看到了Hibernate神奇魔法的5%,它足夠的複雜強大,可以讓你應付複雜的應用。

one-to-one關係
在絕大多數系統當中不可能只存在一個數據表格,否則就違背了關係資料庫的初衷。表與表的關係比較複雜,可以分為幾種情況:

● 一對一關聯(one to one)
● 一對多關聯(one to many)
● 多對一關聯(many to one)
● 多對多關聯(many to many)

按順序來講。假設一個一對一關聯的例子是:
表格:person
id 編號(主鍵)
name 姓名
email email地址

表格:spouse
id 編號(外鍵)
name 姓名

person這個表保存用戶信息,而spouse保存用戶配偶的信息。在一般情況下一個人只有一個配偶,這很適合我們一對一的情況。如果你對婚外戀感興趣的話,我們可以在一對多和多對一的關聯中討論這個問題,也許還可以在多對多中^_^(禽獸!)。

OK,下面設計POJO:
Person這個類非常簡單:

/*
* Created on 2004-4-19
*/
package org.bromon.zizz;

/**
* @author Bromon
*/
public class Person
{
private int id;
private String name;
private String email;

public void setId(int id)
{
this.id=id;
}
public int getId()
{
return(id);
}

public void setName(String name)
{
this.name=name;
}
public String getName()
{
return(name);
}

public void setEmail(String email)
{
this.email=email;
}
public String getEmail()
{
return(email);
}
}


然後編寫它的映射規則,這個應該能夠理解了:
< ?xml version="1.0"? >
< !DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

< hibernate-mapping package="org.bromon.zizz" >
< class name="Person" table="person" lazy="true" >
< id name="id" type="integer" unsaved-value="null" >
< column name="id" sql-type="int" not-null="true"/ >
< generator class="identity"/ >
< /id >

< property name="name" column="name" not-null="true" unique="false"/ >
< property name="email" column="email" not-null="false"/ >
< /class >
< /hibernate-mapping >

so easy是不是?一切都按部就班。下面是Souse類:

/*
* Created on 2004-4-20
*/
package org.bromon.zizz;

/**
* @author Bromon
*/
public class Spouse
{
private int id;
private String name;
private Person person;

public void setId(int id)
{
this.id=id;
}
public int getId()
{
return(id);
}

public void setName(String name)
{
this.name=name;
}
public String getName()
{
return(name);
}

public void setPerson(Person person)
{
this.person=person;
}
public Person getPerson()
{
return(person);
}
}


注意裡面的域person。它的映射文件:

< ?xml version="1.0"? >
< !DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

< hibernate-mapping package="org.bromon.zizz" >
< class name="Spouse" table="spouse" lazy="true" >
< id name="id" type="integer" unsaved-value="null" >
< column name="id" sql-type="int" not-null="true"/ >
< generator class="foreign" >
< param name="property" >person< /param >
< /generator >
< /id >

< property name="name" column="name" not-null="true" unique="false"/ >
< one-to-one name="person" class="Person" cascade="all" constrained="true" / >
< /class >
< /hibernate-mapping >

這裡指明了id的generator是一個外鍵,和person相關聯。然後指定一個one-to-one關係,不難理解是不是?Hibernate的確很符合我們的思維習慣。需要提醒的是,這種關聯關係是單向的,Person並不需要去指定Spouse。

下面來操作這兩個類:

/*
* Created on 2004-4-20
*/
package org.bromon.zizz;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import net.sf.hibernate.tool.hbm2ddl.*;
/**
* @author Bromon
*/
public class OperateSpouse
{
public static void main(String args[])
{
try
{
Configuration cfg=new Configuration().addClass(Spouse.class);
cfg.addClass(Person.class);
SessionFactory factory=cfg.buildSessionFactory();
new SchemaExport(cfg).create(true,true);
Session session=factory.openSession();

Person person=new Person();
person.setName("bromon");
person.setEmail("bromon@163.com");

Spouse spouse=new Spouse();
spouse.setName("who");
spouse.setPerson(person);

Transaction ts=session.beginTransaction();
session.save(person);
session.save(spouse);
ts.commit();
session.close();
}catch(Exception e)
{
System.out.println(e);
}
}
}


這個例子和第一篇中的例子非常相似。OK,執行一下,然後看看zizz資料庫,搞掂。

Many-to-One關係

很明顯一對多或者多對一關係是關係資料庫中非常常見的現象,下面通過父親-兒子的例子來演示一對多關係,多對一關係是類似的,不過在我們的這個例子中不宜採用,否則會帶來倫理學上的問題。

首先定義Child類:
/*
* Created on 2004-5-8
*/
package org.bromon.zizz;

/**
* @author Bromon
*/
public class Child
{
private int id;
private String name;
private int fatherId;
private Person father;

public Child(){}

/**
* @return
*/
public Person getFather()
{
return father;
}

/**
* @return
*/
public int getFatherId()
{
return fatherId;
}

/**
* @return
*/
public int getId()
{
return id;
}

/**
* @return
*/
public String getName()
{
return name;
}

/**
* @param person
*/
public void setFather(Person p)
{
father = p;
}

/**
* @param i
*/
public void setFatherId(int i)
{
fatherId = i;
}

/**
* @param i
*/
public void setId(int i)
{
id = i;
}

/**
* @param string
*/
public void setName(String string)
{
name = string;
}

}

這裡的fatherId是外鍵,關聯person表的id欄位。

下面是映射文件Child.hbm.xml:
< ?xml version="1.0"? >
< !DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

< hibernate-mapping package="org.bromon.zizz" >
< class name="Child" table="child" lazy="true" >
< id name="id" type="integer" unsaved-value="null" >
< column name="id" sql-type="int" not-null="true"/ >
< generator class="identity"/ >
< /id >

< property name="name" column="name" not-null="true" unique="false"/ >
< many-to-one name="father" column="fatherid" / >

< /class >
< /hibernate-mapping >
需要注意的是fatherId並沒有做為一個property被映射,而是在many-to-one聲明中使用。

需要對Person..java做修改,添加以下代碼:

import java.util.*;

private Set children=new HashSet();
/**
* @return
*/
public Set getChildren()
{
return children;
}
/**
* @param set
*/
public void setChildren(Set set)
{
children = set;
}

然後修改Person.hbm.xml,對添加的代碼做映射:

< set name="books" lazy="true" inverse="true" cascade="all" >
< key column="fatherid"/ >
< one-to-many class="Child" / >
< /set >

這裡的key column是child表的外鍵,inverse需要指定為true。

下面做操作一下,功能是查詢person表中id=1的記錄,作為小孩的父親,然後給child表添加一條新記錄。

/*
* Created on 2004-5-8
*/
package org.bromon.zizz;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import net.sf.hibernate.tool.hbm2ddl.*;
/**
* @author Bromon
*/
public class OperateChild
{
/**
* @param args
*/
public static void main(String args[])
{
try
{
Configuration cfg = new Configuration().addClass(Person.class);
cfg.addClass(Child.class);
SessionFactory sessions = cfg.buildSessionFactory();
new SchemaExport(cfg).create(true, true);
Session session = sessions.openSession();

Child c=new Child();

/*Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1");
Person p=(Person)q.list().get(0);*/

Person p=(Person)session.find("from org.bromon.zizz.Person as p where p.id=?",new Integer(1),Hibernate.INTEGER).get(0);
System.out.println(p.getName());
c.setName("andy");
c.setFather(p);

Transaction ts = session.beginTransaction();
session.save(c);
ts.commit();
session.close();
} catch (Exception e)
{
System.out.println(e);
}
}
}

被註釋掉的部分是HQL的另外一種查詢方法。在這個例子中可以看出對象的查詢非常容易,不需要自己再去封裝數據,修改和刪除對象也很容易:

//得到一個對象
Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1");
Person p=(Person)q.list().get(0);

//修改數據
p.setName(「Mr Smith」);

//保存數據
session.save(p);
session.flush();

//刪除數據
session.delete(p);
session.flush();

[火星人 ] Java企業應用-Hibernate實戰全解已經有795次圍觀

http://coctec.com/docs/linux/show-post-189728.html