Hibernate查詢

??

9.1? Hibernate數據查詢

數據查詢與檢索是Hibernate的一個亮點。Hibernate的數據查詢方式主要有3種,它們是:

l???????? Hibernate Query Language(HQL)

l???????? Criteria Query

l???????? Native SQL

下面對這3種查詢方式分別進行講解。

9.1.1? Hibernate Query Language(HQL)

Hibernate Query Language(HQL)提供了十分強大的功能,推薦大家使用這種查詢方式。HQL具有與SQL語言類似的語法規范,只不過SQL針對表中字段進行查 詢,而HQL針對持久化對象,它用來取得對象,而不進行update、delete和insert等操作。而且HQL是完全面向對象的,具備繼承、多態和 關聯等特性。

1.from子句

from字句是最簡單的HQL語句,例如 from Student,也可以寫成select s from Student s。它簡單地返回Student類的所有實例。

除了Java類和屬性的名稱外,HQL語句對大小寫并不敏感,所以在上一句HQL語句中,from與FROM是相同的,但是Student與student 就不同了,所以上述語句寫成from student就會報錯。下列程序演示如何通過執行from語句取得所有的Student對象。

Query query = session.createQuery(“from Student”);

List list = query.list();

for (int i=0;i<list.size(); i++)

{

??? Student stu = (Student)list.get(i);

??? System.out.println(stu.getName());

}

如果執行HQL語句“from Student, Course”,并不簡單地返回兩個對象,而是返回這兩個對象的的笛卡兒積,這類似于SQL語句中字段的全外連接。在實際應用中,像“from Student, Course”這樣的語句幾乎不會出現。

2.select子句

有時并不需要得到對象的所有屬性,這時可以使用select子句進行屬性查詢,例如,select s.name from Student s。下面程序演示如何執行這個語句:

Query query = session.createQuery(“select s.name from Student s”);

List list = query.list();

for (int i=0;i<list.size(); i++) {

??? String name = (String)list.get(i);

??? System.out.println(ame());

}

如果要查詢兩個以上的屬性,查詢結果會以數組的方式返回,如下所示:

Query query = session.createQuery(“select s.name, s.sex from Student as s”);

List list = query.list();

for (int i=0;i<list.size(); i++) {

??? Object obj[] = (Object[])list.get(i);

??? System.out.println(ame(obj[0] + “的性別是:” +obj[1]));

}

在使用屬性查詢時,由于使用對象數組,操作和理解都不太方便,如果將一個object[]中所有成員封裝成一個對象就方便多了。下面的程序將查詢結果進行了實例化:

Query query = session.createQuery(“select new Student(s.name, s.sex) from Student s”);

List list = query.list();

for (int i=0;i<list.size(); i++) {

??? Student stu = (Student)list.get(i);

??? System.out.println(stu.getName());

}

要正確運行以上程序,還需要在Student類中加入一個如下的構造函數:

public Student(String name, String sex)

{

??? this.name = name;

??? this.sex = sex;

}

3.統計函數查詢

可以在HQL中使用函數,經常使用的函數有:

l???????? count():統計記錄條數

l???????? min():求最小值

l???????? max():求最大值

l???????? sum():求和

l???????? age():求平均值

例如,要取得Student實例的數量,可以編寫如下HQL語句:

select count(*) from Student

取得Student的平均年齡的HQL語句如下:

select avg(s.age) from Student as s

可以使用distinct去除重復數據:

select distinct s.age from Student as s

4.where子句

HQL也支持子查詢,它通過where子句實現這一機制。where子句讓用戶縮小要返回的實例的列表范圍,例如下面語句會返回所有名字為“Bill”的Student實例:

Query query = session.createQuery("from Student as s where s.name='Bill' ");

where子句允許出現的表達式包括了SQL中可以使用的大多數情況:

l???????? 數學操作:+,-,*,/

l???????? 真假比較操作:=,>=,<=,<>,!=,like

l???????? 邏輯操作:and,or, not

l???????? 字符串連接:||

l???????? SQL標量函數:例如upper()和lower()

如果子查詢返回多條記錄,可以用以下的關鍵字來量化:

l???????? all:表示所有的記錄。

l???????? any:表示所有記錄中的任意一條。

l???????? some:與any用法相同。

l???????? in:與any等價。

l???????? exists:表示子查詢至少要返回一條記錄。

例如,下面語句返回所有學生的年齡都大于22的班級對象:

from Group g where 22<all (select s.age from g.students s)

下述語句返回在所有學生中有一個學生的年齡等于22的班級:

from Group g where 22=any (select s.age from g.students s)

或者

from Group g where 22=some (select s.age from g.students s)

或者

from Group g where 22 in (select s.age from g.students s)

5.order by 子句

查詢返回的列表可以按照任何返回的類或者組件的屬性排序:

from Student s order by s.name asc

asc和desc是可選的,分別代表升序或者降序。

6.連接查詢

與SQL查詢一樣, HQL也支持連接查詢,如內連接、外連接和交叉連接。

l???????? inner join:內連接

l???????? left outer join:左外連接

l???????? right outer join:右外連接

l???????? full join:全連接,但不常用

下面重點講解內連接查詢,左外連接和右外連接查詢和內連接大同小異,而全連接幾乎不怎么使用。

inner join可以簡寫為join,例如在查詢得到Group對象時,內連接取得對應的Student對象,實現的程序如下。

……//打開Session,開啟事務

Student? stu = null;? //聲明Student實例

Group? group = null; //聲明Group實例

Query query = session.createQuery("from Group g join g.students");

List list = query.list();

Object obj[] = null;? //聲明對象數組

for(int i=0;i<list.size();i++)? {

??? obj = (Object[])list.get(i); //取得集合中的第i個數組

??? group = (Group)obj[0];? //group是數組中第一個對象

??? stu = (Student)obj[1];?? //stu是數組中第二個對象

??? System.out.println(stu.getName() + "屬于:" +group.getName() );

}

??? ……//提交事務,關閉Session

9.1.2? Criteria Query方式

當查詢數據時,人們往往需要設置查詢條件。在SQL或HQL語句中,查詢條件常常放在where子句中。此外,Hibernate還支持Criteria 查詢(Criteria Query),這種查詢方式把查詢條件封裝為一個Criteria對象。在實際應用中,使用Session的createCriteria()方法構建一 個org.hibernate.Criteria實例,然后把具體的查詢條件通過Criteria的add()方法加入到Criteria實例中。這樣, 程序員可以不使用SQL甚至HQL的情況下進行數據查詢,如例程9-1所示。

例程9-1? Criteria應用實例

------------------------------------------------------------------------------------------

Criteria cr = session.createCriteria(Student.class); //生成一個Criteria對象

cr.add(Restrictions.eq("name", "Bill"));//等價于where name=’Bill’

List list = cr.list();

Student stu = (Student)list.get(0);

System.out.println(stu.getName());

1.常用的查詢限制方法

在例程9-1中,Restrictions.eq()方法表示equal,即等于的情況。Restrictions類提供了查詢限制機制。它提供了許多方法,以實現查詢限制。這些方法及其他一些criteria常用查詢限制方法列于表9-1中。

表9-1? Criteria Query常用的查詢限制方法

方??? 法

說??? 明

Restrictions.eq()

equal,=

Restrictions.allEq()

參數為Map對象,使用key/value進行多個等于的對比,相當于多個Restrictions.eq()的效果

Restrictions.gt()

greater-than, >

Restrictions.lt()

less-than, <

Restrictions.le()

less-equal, <=

Restrictions.between()

對應SQL的between子句

Restrictions.like()

對應SQL的like子句

Restrictions.in()

對應SQL的in子句

Restrictions.and()

and關系

Restrictions.or()

or關系

Restrictions.isNull()

判斷屬性是否為空,為空返回true,否則返回false

Restrictions.isNotNull()

與Restrictions.isNull()相反

Order.asc()

根據傳入的字段進行升序排序

Order.desc()

根據傳入的字段進行降序排序

MatchMode.EXACT

字符串精確匹配,相當于“like 'value'”

MatchMode.ANYWHERE

字符串在中間位置,相當于“like '%value%'”

MatchMode.START

字符串在最前面的位置,相當于“like 'value%'”

MatchMode.END

字符串在最后面的位置,相當于“like '%value'”

例1:查詢學生名字以t開頭的所有Student對象。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(“name”, “t%”))

List list = cr.list();

Student stu = (Student)list.get(0);

或者使用另一種方式:

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(“name”, “t”, MatchMode.START))

List list = cr.list();

Student stu = (Student)list.get(0);

例2:查詢學生姓名在Bill, Jack和Tom之間的所有Student對象。

String[] names = {“Bill”, “Jack”, “Tom”}

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.in(“name”, names))

List list = cr.list();

Student stu = (Student)list.get(0);

例3:查詢學生的年齡age等于22或age為空(null)的所有Student對象。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.eq(“age”, new Integer(22));

cr.add(Restrictions.isNull(“age”));

List list = cr.list();

Student stu = (Student)list.get(0);

例4:查詢學生姓名以字母F開頭的所有Student對象,并按姓名升序排序。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(“name”, “F%”);

cr.addOrder(Order.asc(“name”));

List list = cr.list();

Student stu = (Student)list.get(0);

Tips

?

調用Order.asc的方法應是Criteria的addOrder()方法。

2.連接限制

在Criteria 查詢中使用FetchMode來實現連接限制。在HQL語句中,可以通過fetch關鍵字來表示預先抓取(Eager fetching),如下所示:

from Group g

left join fetch g.students s

where g.name like ' 05'

可以使用Criteria的API完成同樣的功能,如下所示:

Criteria cr = session.createCriteria(Group.class);

cr.setFetchMode(“students”, FetchMode.EAGER);

cr.add(Restrictions.like(“name”, “2005”, MatchMode.END))

List list = cr.list();

以上兩種方式編寫的代碼,都使用相同的SQL語句完成它們的功能,如下所示:

select g.*, s.* from Group g

left outer join Student s

on g.id = s.group_id

where g.name like ' 05'

9.1.3? Native SQL查詢

本地SQL查詢(Native SQL Query)指的是直接使用本地數據庫(如Oracle)的SQL語言進行查詢。它能夠掃清你把原來直接使用SQL/JDBC 的程序遷移到基于 Hibernate應用的道路上的障礙。

Hibernate3允許你使用手寫的SQL來完成所有的create、update、delete和load操作(包括存儲過程)。

1.創建一個基于SQL的Query

Native SQL查詢是通過SQLQuery接口來控制的,它是通過調用Session.createSQLQuery()方法來獲得的,例如:

String sql = "select {s.*} from t_student s where s.age>22";

SQLQuery slqQuery = session.createSQLQuery(sql);

sqlQuery.addEntity("s", Student.class);

List list = sqlQuery.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() +" "+ stu.getName());

}

createSQLQuery(String sql)利用傳入的SQL參數構造一個SQLQuery實例(SQLQuery是Query的子接口)。使用這個方法時,還需要傳入查詢的實體類,因此要配合SQLQuery的addEntity()方法一起使用。

addEntity()方法是將實體類別與別名聯系在一起的方法,此方法的定義如下:

public SQLQuery addEntity(String alias, Class entityClass)

{}號用來引用數據表的別名,例如以上代碼中{s.*}表示使用s來作為t_student表的別名。

2.命名SQL查詢

與HQL的命名查詢相似,也可以將本地的SQL查詢語句定義在映射文件中,然后像調用一個命名HQL查詢一樣直接調用命名SQL查詢。

例如在Student.hbm.xml中定義一個命名SQL查詢,如下所示:

<hibernate-mapping>

<class name="Student" table="student" lazy="false">

……

</class>

<sql-query name="QueryStudents">

<![CDATA[

???????????? select {s.*} from t_student s where s.age>22

]]>

<return alias="s" class="Student"/>

</sql-query>

</hibernate-mapping>

<sql- query>元素是<hibernate-mapping>元素的一個子元素。利用<sql-query>元素的子元素<return>指定別名與實體類相關聯。配合映射文件中的定義,編寫如下代碼來調用這個命名SQL查詢:

Query query = session.getNamedQuery(“QueryStudents”);

List list = query.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() + “ ”+ stu.getName());

}

也可以在命名查詢中設定查詢參數,如下所示:

……

<sql-query name=”QueryStudents”>

??? <![CDATA[

??????? select {s.*} from t_student s where s.age>:age

??? ]]>

??? <return alias=”s” class=”Student”/>

</sql-query>

…..

編寫如下代碼來調用這個命名SQL查詢,并且把查詢中定義的參數傳入:

Query query = session.getNamedQuery(“QueryStudents”);

query.setInteger(“age”,22);

List list = query.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() + “ ”+ stu.getName());

}

3.自定義insert、update和delete語句

Hibernate3.x 的映射文件中新添了<sql-insert>、<sql-update> 和<sql-delete>3個標記。可以使用這3個標記自定義自己的insert、update和delete語句,例如在 Student.hbm.xml中定義這些語句如下:

<hibernate-mapping>

<class name="Student" table="student" lazy="false">

<id name="id" unsaved-value="null" type="string" column="id">

??? <generator class="uuid.hex"/>

<property name="name" type="string" />

<property name="age" type="int" />

<sql-insert> <!--insert語句-->

??? insert into t_student(name, age, id) values(?,?,?)

??? </sql-insert>

??? <sql-update> <!--update語句-->

??? update t_student set name=?, age=? where id=?

??? </sql-update>

??? <sql-delete> <!--delete語句-->

??????? delete from t_student where id=?

</sql-delete>

</class>

</hibernate-mapping>

對于上述文件中自定義的SQL語句,要注意以下幾點。

l???????? insert和update語句中定義的字段必須和映射文件聲明的屬性相對應,一個都不能少。

l???????? 在insert和update語句中,屬性出現的順序必須和映射文件中聲明的順序一致。

l???????? 在insert語句中,主鍵id總是放在最后。

在程序中實現以上自定義的insert語句如下:

……

Student stu = new Student();

stu.setName(“Bill”);

stu.setAge(22);

session.save(stu);

運行上述程序,控制臺顯示的信息如下:

Hibernate: insert into t_student(name,age,id) values(?,?,?)

如果不想在insert或update語句中包括所有屬性,則可以在屬性定義時,加上insert="false"或update="false",如下所示:

<property name=”name” type=”string” insert=”false” update=”false” />

??? <sql-insert>? insert into t_student(age, id) values(?,?)? </sql-insert>

<sql-update> update t_student set age=? where id=?? </sql-update>

實例:

9.2? 利用關聯關系操縱對象

數據對象之間關聯關系有一對一、一對多及多對多關聯關系。在數據庫操作中,數據對象之間的關聯關系使用JDBC處理很困難。本節講解如何在 Hibernate中處理這些對象之間的關聯關系。本節使用到4個類,它們分別是Student(學生)、Card(學生證)、Group(班級)和 Course(課程),它們之間的關聯關系如圖9-1所示。這些實體存在級聯(cascade)問題。例如,當刪除一個班級的信息時,還要刪除該班的所有 學生的基本信息。如果直接使用JDBC執行這種級聯操作,會非常煩瑣。Hibernate通過把實體對象之間關聯關系及級聯關系在映射文件中聲明,比較簡 便地解決了這類級聯操作問題。

圖9-1? 對象關聯圖

9.2.1? 一對一關聯關系的使用

一對一關系在實際生活中是比較常見的,例如學生與學生證的關系,通過學生證可以找到學生。一對一關系在Hibernate中的實現有兩種方式,分別是主鍵關聯和外鍵關聯。

1.以主鍵關聯

主鍵關聯的重點是,關聯的兩個實體共享一個主鍵值。例如,Student與Card是一對一關系,它們在數據庫中對應的表分別是t_student和 t_card。它們共用一個主鍵值id,這個主鍵可由t_student表或t_card表生成。問題是如何讓另一張表引用已經生成的主鍵值呢?例 如,t-student表填入了主鍵id的值,t_card表如何引用它?這需要在Hibernate的映射文件中使用主鍵的foreign生成機制。

為了表示Student與Card之間的一對一關聯關系,在Student和Card的映射文件Student.hbm.xml和Card.hbm.xml中都要使用<one-to-one>標記,如例程9-2所示。

例程9-2? Student.hbm.xml

-----------------------------------------------------------------------------------------------

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

??? "-//Hibernate/Hibernate Mapping DTD//EN"

??? "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping>

<class name="test.Student" table="T_STUDENT" lazy="true"><!-- 把類與表關聯起來-->

<id name="id" column="id" type="int">

<generator class="increment" />

</id>

<property name="name" column="NAME" type="string" />

<!--property name="card_id" column="CARD_ID" type="int" /--> <!--映射學生證號-->

<property name="sex" column="SEX" type="string" />

<property name="age" column="AGE" type="int" />

<one-to-one? name="card"? class="test.Card"

??? fetch="join" cascade="all"? />

</class>

</hibernate-mapping>

<class>元素的lazy屬性設定為true,表示延遲加載,如果lazy的值設置為false,則表示立即加載。下面對立即加載和延遲加載這兩個概念進行說明。

l???????? 立即加載:表示Hibernate在從數據庫中取得數據,組裝好一個對象(比如學生1)后,會立即再從數據庫取得數據,組裝此對象所關聯的對象(例如學生證1)。

l???????? 延遲加載:表示Hibernate在從數據庫中取得數據,組裝好一個對象(比如學生1)后,不會立即再從數據庫取得數據,組裝此對象所關聯的對象(例如學生證1),而是等到需要時,才會從數據庫取得數據,組裝此關聯對象。

<one-to-one>元素的cascade屬性表明操作是否從父對象級聯到被關聯的對象,它的取值如下。

l???????? none:在保存、刪除或修改對象時,不對其附屬對象(關聯對象)進行級聯操作。這是默認設置。

l???????? save-update:在保存、更新當前對象時,級聯保存、更新附屬對象(臨時對象、游離對象)。

l???????? delete:在刪除當前對象時,級聯刪除附屬對象。

l???????? all:在所有情況下均進行級聯操作,即包含save-update和delete操作。

l???????? delete-orphan:刪除和當前對象解除關系的附屬對象。

<one-to-one>元素的fetch屬性的可選值是join和select,默認值是select。當fetch屬性設定為join時,表示連接抓取(Join fetching : Hibernate通過 在SELECT語句使用OUTER JOIN(外連接)來獲得對象的關聯實例或者關聯集合。 當fetch屬性設定為select時,表示查詢抓取(Select fetching:需要另外發送一條 SELECT 語句抓取當前對象的關聯實體或集合。

例程9-3中<one-to-one>元素的cascade屬性設置為“all”,表示增加、刪除及修改Student對象時,都會級聯增加、刪除和修改Card對象。

例程9-3? Card.hbm.xml

-----------------------------------------------------------------------------------------------

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

??? "-//Hibernate/Hibernate Mapping DTD//EN"

??? "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping>

<class name="test.Card" table="t_card" lazy="true"><!-- 把類與表關聯起來-->

<id name="id" column="id">

<generator class="foreign" >

??? <param name="property">student</param>

??? </generator>

</id>

<one-to-one name="student"? class="test.Student" constrained="true"/>

<property name="name" column="name" type="string" />

<!-- one-to-one name="student"? class="test.Student" constrained="true"/-->

</class>

</hibernate-mapping>

在例程9-3中,Card.hbm.xml的主鍵id使用外鍵(foreign)生成機制,引用代號為“student”對象的主鍵作為Card表的主鍵 和外鍵。student在該映射文件的<one-to-one>元素中進行了定義,它是Student對象的代號。<one-to- one>元素的屬性Constrained="true"表示Card引用了student的主鍵作為外鍵。

需要特別注意的是,Student類中要相應地加入一對get/set方法:

public Card getCard() {

??? return this.card;???

??? }

??? public void setCard(Card card) {

this.card = card;

}

在Card類中也要相應地加入一對get/set方法:

public Student getStudent() {

??? return this.stu;

??? }

public void setStudent(Student stu) {

??? this.stu = stu;

}

在客戶端測試程序中操縱Student和Card對象的方法如例程9-4所示。

例程9-4? 客戶端測試程序

package test;

import org.hibernate.*;

import org.hibernate.cfg.*;

import java.io.File;

import java.util.List;

public class Test {

??? public static void main(String[] args) {

?????????????????

??????? File file = new File("D:\\eclipse3.2\\workspace\\HibernateTest\\hibernate.cfg.xml");

?????????????????

??????? Configuration? conf = new Configuration().configure(file);

?????????????????

??????? SessionFactory? sf = conf.buildSessionFactory();

?????????????????

??????? Session session = sf.openSession();

?????????????????

??????? Transaction tx = session.beginTransaction();

?????????????????

??????? //新建Student對象

??????? Student stu = new Student();

??????????? stu.setName("Walker");

??????????? stu.setSex("male");

??????????? stu.setAge(22);

??????????? //新建Card對象

??????????? Card card = new Card();

??????????? card.setName("Walker");

???????????????????????????

??????? //設置Student對象與Card對象之間的關聯

??????? stu.setCard(card);

??????? card.setStudent(stu); //此句不能省略,否則card將不知從何處取得主鍵值

????????

??????? try {

??????????? session.save(stu);

??????? tx.commit();

??????? session.close();

??????? System.out.println("Data have been inserted into DB.");

??????? } catch (HibernateException e) {

??????????? e.printStackTrace();

??????????? tx.rollback();

??????? session.close();

??????? }???

??? }

}

運行以上代碼后,將會在t_student表和t_card表中插入相應的數據。

2.以外鍵關聯

以外鍵關聯的要點是:兩個實體各自有不同的主鍵,但其中一個實體有一個外鍵引用另一個實體的主鍵。例如,假如Student和Card是外鍵關聯的一對一 關系,它們在數據庫中相應的表分別是t_student表和t_card表,t_student表有一個主鍵id,t_card表有一個主鍵id和一個外 鍵 stu_id,此外鍵對應student表的主鍵id。

Student的映射文件Student.hmb.xml見例程9-2。但Card的映射文件Card.hbm.xml要做相應變動,如例程9-5所示。

例程9-5? Card.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="test.Card" ?table="T_CARD" lazy= "true"><!--把類與表關聯起來-->

<id name="id" >

<generator class="increment" ><!--不再是foreign了-->

??? </generator>

</id>

<property name="name" column="NAME" type="string" />

<many-to-one? name="student"? class="Student" column="stu_id"

??? unique="true"/> <!--唯一的多對一,實際上變成一對一關系了-->

</class>

</hibernate-mapping>

在例程9-5中,<many-to-one>元素的name屬性聲明外鍵關聯對象的代號,class屬性聲明該外鍵關聯對象的類,column屬性聲明該外鍵在數據表中對應的字段名,unique屬性表示使用DDL為外鍵字段生成一個唯一約束。

以外鍵關聯對象的一對一關系,其實本質上變成了一對多的雙向關聯了,應直接按照一對多和多對一的要求編寫它們的映射文件。當<many-to-one>元素的unique屬性設定為true,多對一的關系實際上變成了一對一的關系。

在客戶端程序中操縱外鍵關聯一對一關系的對象的方法見例程9-4。

9.2.2? 一對多關聯關系的使用

一對多關系很常見,例如父親和孩子、班級與學生的關系就是很好的一對多的關系。在實際編寫程序時,一對多關系有兩種實現方式:單向關聯和雙向關聯。單向的 一對多關系只需在一方進行映射配置,而雙向的一對多需要在關聯的雙方進行映射配置。下面以Group(班級)和Student(學生)為例講解如何配置一 對多的關系。

1.單向關聯

單向的一對多關系只需在一方進行映射配置,所以我們只配置Group(班級)的映射文件Group.hbm.xml,如例程9-6所示。

例程9-6? Group.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="test.Group" table="T_GROUP" lazy="true"><!--把類與表關聯起來-->

<id name="id" column="ID"type="int">

<generator class="increment" >

??? </generator>

</id>

<property name="name" column="NAME" type="string"

??? update="true" insert="true" />

<set? name="students"

??? table="T_STUDENT"

??? lazy="false"

??? inverse="false"

??? cascade="all"

??? sort="unsorted"

>?

<key column="ID"/>

<one-to-many class="test.Student"/>

</set>

</class>

</hibernate-mapping>

在以上映射文件中,<property>元素的insert屬性表示被映射的字段是否出現在SQL的 INSERT語句中;update屬性表示被映射的字段是否出現在SQL的 UPDATE語句中。

<set>元素描述的字段(本例中為students)對應的類型為java.util.Set,它的各個屬性的含義如下。

l???????? name:字段名,本例的字段名為students,它屬于java.util.Set類型。

l???????? table:關聯表名,本例中,students的關聯數據表名是t_student。

l???????? lazy:是否延遲加載,lazy=false表示立即加載。

l???????? inverse:用于表示雙向關聯中的被動方的一端,inverse的值為false的一方負責維護關聯關系。默認值為false。本例中Group將負責維護它與Student之間的關聯關系。

l???????? cascade:級聯關系;cascade=all表示所有情況下均進行級聯操作,即包含save-update和delete操作。

l???????? sort:排序關系,其可選取值為unsorted(不排序)、natural(自然排序)、comparatorClass(由某個實現了java.util.comparator接口的類型指定排序算法)。

<key>子元素的column屬性指定關聯表(本例中t_student表)的外鍵,<one-to-many>子元素的class屬性指定了關聯類的名字。

此外,在Group類中增加如下get/set方法:

private Set students;

??? public Set getStudents() {

??????? return this.students;

??? }

??? public void setStudents(Set stu) {

??????? this.students = stu;

}

假如我們想為一個班級添加一個學生對象,實現的代碼如下:

Transaction tx = session.beginTransaction();

Student stu = new Student();

stu.setName("Walker");

stu.setSex("male");

stu.setAge(22);

group.getStudents().add(stu);

session.save(group);

tx.commit();

2.雙向關聯

如果要設置一對多雙向關聯,那么還需要在“多”方的映射文件中使用<many-to-one>標記。例如,在Group與Student一對 多的雙向關聯中,除了Group的映射文件Group.hbm.xml和Group類進行設置和修改外,還需要在Student的映射文件 Student.hbm.xm中加入:

<many-to-one

??????? name="group"

??????? class="test.Group"

??????? cascade="none"

??????? outer-join="auto"

??????? update="true"

??????? insert="true"

??????? column="ID"

??????? />

name、class等屬性前面已經解釋過了,這里只說明insert和update屬性。insert和update設定是否對column屬性指定的關聯字段進行insert和update操作。在Student類還要相應添加一對get/set方法:

public Group getGroup() {

??? return this.group;

??? }

??? public void setGroup(Group g) {

??????? this.group = g;

??? }

此外,把Group.hbm.xml(如例程9-6所示)中的<set>元素的inverse屬性的值設定為true,如下所示。

<set? name="students" table="T_STUDENT" lazy="false"

??? inverse="true" cascade="all" sort="unsorted">

<key column="ID"/>

<one-to-many class="Student"/>

</set>

當 Group.hmb.xml中<set>元素的inverse屬性的值設定為false時,Group和Student之間的關聯關系由 Group維護,Group負責將自己的id告訴Student,然后Hibernate發送update語句去更新記錄。但現在inverse的值設定 為true后,Group和Student之間的關聯關系轉由Student來維護,由Student自動去取得Group的id,而這個Student 取得Group的id的動作,其實就是完成一個“學生添加到班級”的動作。

9.2.3? 多對多關聯關系的使用

Student(學生)和Course(課程)的關系就是多對多的關系。在映射多對多關系時,需要另外使用一個連接表(例如,Student_Course)。 Student_Course表包含2個字段:CourseId和StuId。此外,在它們的映射文件中使用<many-to-many>標記。

Student的映射文件Student.hbm.xml中加入以下描述信息:

<set? name="courses" ?table=" Student_Course" lazy="false"

? ??inverse="false" cascade="save-update" >

<key column="StuId"/>

<many-to-many class="test.Course" column="CourseId" />

</set>

相應地,Course的映射文件Course.hbm.xml加入以下描述信息:

<set? name="students" ?table=" Student_Course" lazy="false"

inverse="true" cascade="save-update" >

<key column="CourseId"/>

<many-to-many class="test.Student" column="StuId"? />

</set>

1.添加關聯關系

首先讓我們編一個程序來看看一個名為Bill的學生選擇了什么課程:

……

//獲得包含Bill的Student對象

Student stu = (Student) session.createQuery(“from Student s where s.name =

‘Bill’ ”)?.uniqueResult();

List ls = new ArrayList(stu.getCourses());

for(int i=0; i<ls.size(); i++) {

??? Course course = (Course)ls.get(i);? //獲得Course對象

??? System.out.println(course.getName()); //打印Bill所選課程的清單

}

…..

現在Bill還想選修business課程,這對于程序員來說只是為Bill添加了一個到business的關聯,也就是說在student_course表中新添一條記錄,而T_Student 和T_Course表都不用變更。

……

Student stu = (Student) session.createQuery(“from Student s where s.name = ‘Bill’ ”)?.uniqueResult();

Course course = (Course) session.createQuery(“from Course c where c.name =

‘business’ ”)?.uniqueResult();

//設置stu與course的相互關系

stu.getCourses().add(course);

course.getStudents().add(stu);

…..

2.刪除關聯關系

刪除關聯關系比較簡單,直接調用對象集合的remove()方法刪除不要的對象即可。例如,要從學生Bill的選修課清單中刪除politics和chemistry兩門課,程序如下:

…….

Student stu = (Student) session.createQuery("from Student s where s.name = 'Bill' ")?.uniqueResult();

Course course1 = (Course) session.createQuery("from Course c where c.name =

'politics' ")?.uniqueResult();

Course course2 = (Course) session.createQuery("from Course c where c.name =

'chemistry' ")?.uniqueResult();

stu.getCourse().remove(course1); //刪除politics課程

stu.getCourse().remove(course2); //刪除chemisty課程

…….

運行以上語句將從student_course表中刪除這兩條記錄,但T_Student和T_Course表沒有任何變化。

0

0

閱讀(1407) 評論 (1) 收藏(0) 轉載(2) 喜歡 打印舉報
已投稿到:
排行榜
前一篇:云空間
后一篇:Oracle?存儲過程
<?前一篇云空間
后一篇?>Oracle?存儲過程

新浪BLOG意見反饋留言板 不良信息反饋 電話:4006900000 提示音后按1鍵(按當地市話標準計費) 歡迎批評指正

新浪簡介 | About Sina | 廣告服務 | 聯系我們 | 招聘信息 | 網站律師 | SINA English | 會員注冊 | 產品答疑

新浪公司 版權所有

幻燈播放

轉載于:https://www.cnblogs.com/CooderIsCool/p/4745774.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/273039.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/273039.shtml
英文地址,請注明出處:http://en.pswp.cn/news/273039.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux x86 io端口映射,linux中的 IO端口映射和IO內存映射

下面是今天看到兩篇關于linux中的 IO端口映射和IO內存映射的文章,時間關系,沒來得及深入理解,有空好好看看CPU地址空間CPU地址空間(一)地址的概念1)物理地址&#xff1a;CPU地址總線傳來的地址&#xff0c;由硬件電路控制其具體含義。物理地址中很大一部分是留給內存條中的內存…

單例模式 創建對象

兩種選擇 1 使用pthread_once&#xff0c; once是類的成員變量 只執行一次Create create的作用是創建一個對象 2 使用 static lock 如下所示&#xff0c;注意lock必須是static的&#xff0c;否則是局部變量&#xff0c;每個線程都有自己的lock&#xff0c;無法保證只執行一次。…

Linux c編譯庫路徑,【一點一點學Linux C】交叉編譯時候如何配置連接庫的搜索路徑...

交叉編譯的時候不能使用本地(i686機器&#xff0c;即PC機器&#xff0c;研發機器)機器上的庫&#xff0c;但是在做編譯鏈接的時候默認的是使用本地庫&#xff0c;即/usr/lib,/lib兩個目錄。因此&#xff0c;在交叉編譯的時候&#xff0c;要采取一些方法使得在編譯鏈接的時候找到…

[NBUT 1458 Teemo]區間第k大問題,劃分樹

裸的區間第k大問題&#xff0c;劃分樹搞起。 #pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #inc…

Linux的軟件包封裝格式有,linux軟件安裝包詳解---全

詳細介紹了常見的四種Linux應用軟件安裝包及其安裝方法。一、解析Linux應用軟件安裝包&#xff0c;通常Linux應用軟件的安裝包有四種&#xff1a;1) tar包&#xff0c;如software-1.2.3-1.tar.gz。他是使用UNIX系統的打包工具tar打包的。2) rpm包&#xff0c;如software-1.2.3-…

人生的第一個博客(●'?'●)??--開博典禮

嘛&#xff0c;說實話&#xff0c;現在才開始&#xff0c;實在是有點晚了&#xff0c;一不小心大學都過去1年了_(:3 」∠)_ 我在專業方面的起步也是相當晚的&#xff0c;身為計算機專業&#xff0c;編程卻從大學才開始正式接觸&#xff0c;進入大學時其他方面的能力也都約等于0…

linux查看運行鐘的tomcat,linux查看tomcat啟動運行日志

Linux0&period;11內核--進程調度分析之2&period;調度[版權所有,轉載請注明出處.出處:http://www.cnblogs.com/joey-hua/p/5596830.html ] 上一篇說到進程調度歸根結底是調用timer_interrupt函數, ...iReport 下載地址iReport 下載地址: https://osdn.jp/projects/sfnet…

8月面試題目收錄

面試題收錄 常見兼容性問題&#xff1f; * png24位的圖片在iE6瀏覽器上出現背景&#xff0c;解決方案是做成PNG8.* 瀏覽器默認的margin和padding不同。解決方案是加一個全局的*{margin:0;padding:0;}來統一。* IE6雙邊距bug:塊屬性標簽float后&#xff0c;又有橫行的margin情況…

linux如何升級php版本升級,Linux?升級php版本

近來因工作需要,又沒有服務器維護人員,只能自己上陣啦。從php5.3.28->5.5.30,先自己下載php包到/usr/local/下?&#xff0c;# 解壓縮安裝包tar zxvf php-5.5.30.tar.gz# 進入目錄cd php-5.5.30// 編譯的時候一定要加入參數--enable-fpm#./configure --prefix/usr/local/php…

opencv配置

OpenCV的簡單安裝和一次性配置在這里就不贅述了&#xff0c;網上教程很多&#xff0c;可以參考一下這個鏈接里面的教程http://wenku.baidu.com/view/3b40de25453610661ed9f46b.html。 但是很多情況下面&#xff0c;我們新建一個項目就要重新配置一次OpenCV&#xff0c;那就相當…

linux ftp 工作過程,linux中ftp的安裝過程記錄[運維篇]

安裝FTP的全過程記錄&#xff0c;對于相同情況希望有所幫助。【centOS】1、查詢本機是否安裝vsftpd: rpm -qa |grep vsftpd &#xff1b;2、安裝ftp服務 yum install vsftpd;3、開啟ftp服務 chkconfig vsftpd on&#xff0c;開機啟動&#xff1b;4、手動操作ftp服務&#xff0c…

代碼命名,代碼里的命名規則:錯誤的和正確的對比 命名方法總結 “自我描述的源代碼”用代碼表達出你的思想,讓其他人通過代碼能明白你的意圖。...

http://www.aqee.net/express-names-in-code-bad-vs-clean/ 編程初學者總是把大量的時間用在學習編程語言&#xff0c;語法&#xff0c;技巧和編程工具的使用上。他們認為&#xff0c;如果掌握了這些技術技巧&#xff0c;他們就能成為不錯的程序員。然而&#xff0c;計算機編程…

linux 動態執行cp,Linux常用命令之cp、mv、rm、cat、more、head、tail、ln命令講解

上一章節中&#xff0c;我們了解到了Linux系統的最基礎的幾個文件處理命令&#xff0c;核心的是ls命令&#xff0c;在今天這章中&#xff0c;我們來繼續學習Linux對于文件操作相關的一些命令&#xff0c;比如復制、移動、刪除、查看等命令。1、cp 命令解釋命令名稱&#xff1a;…

使用DBI(perl)實現文本文件的導入導出mysql

DBI 是perl腳本連接數據庫的一個模塊。perl腳本相對shell更靈活&#xff0c;功能更強大&#xff0c;跨平臺能力強。相對可執行jar包要簡單很多。 ?1、下載安裝包DBI-1.631.tar.gzperl腳本下載的網站http://www.cpan.org/ 很多perl的組件都可以在這個網站上下載 2、解壓tar -xz…

linux 車載視頻監控,基于Linux平臺車載視頻監控系統研發-計算機科學與技術專業論文.docx...

基于Linux平臺車載視頻監控系統研發-計算機科學與技術專業論文目錄HYPERLINK \l "_bookmark0" 第一章 緒論1 HYPERLINK \l "_bookmark1" 1.1 研究背景1 HYPERLINK \l "_bookmark2" 1.2 研究動態1 HYPERLINK \l "_bookmark3" 1.3 本文工…

Linux鼠標回報率修改,鼠標回報率怎么調? 設置鼠標回報率的三種方法

鼠標回報率如何設置呢&#xff1f;鼠標回報率又稱刷新率&#xff0c;是指鼠標MCU與電腦傳輸數據頻率。鼠標回報率對于游戲玩家而言至關重要&#xff0c;但同時鼠標回報率與電腦性能息息相關。只有電腦硬件性能良好&#xff0c;才能適當提升鼠標回報率&#xff0c;以實現更高的鼠…

linux下vi修改文件用法

進入vi的命令 vi filename :打開或新建文件&#xff0c;并將光標置于第一行首 vi n filename &#xff1a;打開文件&#xff0c;并將光標置于第n行首 vi filename &#xff1a;打開文件&#xff0c;并將光標置于最后一行首 vi /pattern filename&#xff1a;打開文件&#xff…

linux在芯片設計與實現,基于Linux的Atheros無線芯片網卡驅動的設計與實現

Design and Implementation of Linux based Atheros wireless network cards driverDU Qingbo1杜清波(1985-)&#xff0c;男&#xff0c;碩士研究生&#xff0c;主要研究方向&#xff1a;嵌入式系統與網絡通信1、School of Computer Science,Beijing University of Posts and T…

[轉載]孫婧妍:高考語文148分是這樣煉成的(附:孫婧妍

原文地址&#xff1a;孫婧妍&#xff1a;高考語文148分是這樣煉成的(附&#xff1a;孫婧妍2013高考作文《手機論》)作者&#xff1a; 語文新高考高考語文148分是這樣煉成的 (附&#xff1a;孫婧妍2013高考作文《手機論》) 來源&#xff1a;網絡 作者&#xff1a;孫婧妍…

linux ps 命令安裝,Linux上安裝pstree命令(-bash: pstree: command not found)

一、pstree命令的安裝1、在Mac OS上brew install pstree2、在Fedora/Red Hat/CentOSyum -y install psmisc3、在 Ubuntu/Debianapt-get install psmisc二、pstree命令詳解pstree指令用ASCII字符顯示樹狀結構&#xff0c;清楚地表達程序間的相互關系。如果不指定程序識別碼或用戶…