Professional Documents
Culture Documents
I. Giới thiệu:
Persistence là nói đến khả năng một đối tượng duy trì sự tồn tại sau thời gian sống của chương trình tạo
ra nó. Nếu không có khả năng này, dữ liệu chỉ tồn tại trong bộ nhớ và sẽ mất đi khi bộ nhớ tắt hoặc
máy tính shutdown.
Có một vài loại persistence, ví dụ: khi bạn hiệu chỉnh một file source thì file đó sẽ được persist xuống
đĩa để lần sau rút trích và sử dụng. Các file được lưu trên đĩa là hình thức phổ biến nhất của
persistence. Trong ứng dụng, ví dụ như shopping cart thì persist dữ liệu trong một CSDL quan hệ.
CSDL quan hệ là một sự chọn lựa phổ biến để lưu dữ liệu vì dữ liệu dễ dàng được tạo và truy cập bằng
SQL. Mô hình được sử dụng bởi CSDL quan hệ được gọi là mô hình quan hệ, biểu diễn dữ liệu dưới
dạng bảng hai chiều. Các table có thể liên quan nhau thông qua việc sử dụng khóa chính và khóa ngoại.
Khóa chính đảm bảo không có hai record trong bảng có cùng giá trị. Khóa ngoại tham chiếu đến khóa
chính được lưu trong một bảng khác.
CSDL quan hệ được thiết kế để quản lý dữ liệu theo mô hình quan hệ. Tuy nhiên khi làm việc với các
ứng dụng hướng đối tượng, bạn có thể gặp một số vấn đề khi bạn cố gắng persist các đối tượng vào
trong mô hình quan hệ. Với sự khác biệt của hai mô hình, làm thế nào để chúng làm việc được với
nhau. Để giải quyết vấn đề này object/relational mapping (ORM) ra đời.
ORM là một cầu nối giữa hai mô hình, cho phép ứng dụng của bạn persist các đối tượng trực tiếp vào
CSDL quan hệ mà không cần chuyển đổi qua lại giữa object và relational. Có một vài ORM framework
yêu cầu các đối tượng kế thừa từ lớp cơ bản (base) hoặc yêu cầu xử lý bytecode. Trong khi đó,
Hibernate chỉ yêu cầu một số lượng nhỏ metadata cho mỗi đối tượng persistent. Nó cung cấp đầy đủ
ánh xạ đối tượng/quan hệ, nghĩa là hỗ trợ tất cả các đặc trưng hướng đối tượng mà CSDL quan hệ
thiếu.
Để giải quyết hai bước theo yêu cầu của Hibernate, chúng ta sẽ thảo luận từng vấn đề sau:
• Tạo file cấu hình hibernate.cfg.xml.
• Xây dựng các file định nghĩa ánh xạ để cung cấp cho Hibetnate các thông tin về các lớp
persistent.
• Các lớp được sử dụng để persist và rút trích các lớp.
• Cấu hình nâng cao bao gồm: object caching và quản lý giao dịch.
Trước khi cấu hình Hibernate, đầu tiên bạn nên xác định service giữ kết nối đến CSDL như thế nào.
Kết nối đến CSDL có thể được cung cấp bởi Hibernate hoặc từ JNDI DataSource. Một phương pháp
thứ ba là kết nối JDBC được cung cấp bởi người dùng.
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">uid</property>
<property name="connection.password">pwd</property>
<property name="connection.url">
jdbc:mysql://localhost/db
</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<mapping resource="com/manning/hq/ch03/Event.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Location.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Speaker.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Attendee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Để sử dụng JDBC connection được cung cấp bởi Hibernate, file cấu hình yêu cầu 5 thuộc tính:
connection.driver_class, connection.url, connection.username, connection.password, dialect.
Thuộc tính dialect bảo cho Hibernate biết SQL dialect nào được sử dụng để thao tác. Nó được sử dụng
để đảm bảo các câu Hibernate Query Language (HQL) được chuyển đổi đúng với SQL dialect dưới
CSDL.
Hibernate cũng cần biết vị trí (đường dẫn tương đối so với classpath của ứng dụng) và tên của các
mapping file - mô tả persistent classs.
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory
name="java:comp/env/hibernate/SessionFactory">
<property name="connection.datasource">
jdbc/myDataSource
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<mapping resource="com/manning/hq/ch03/Event.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Location.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Speaker.hbm.xml"/>
<mapping resource="com/manning/hq/ch03/Attendee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Bạn chỉ sử dụng loại cấu hình này khi sử dụng Hibernate với application server: Jboss,
WebSphere...Thuộc tính connection.datasource phải có cùng giá trị với tên của JNDI DataSource trong
cấu hình application server.
Các định nghĩa ánh xạ cho các đối tượng persistent có thể được lưu chung với nhau trong cùng một
file. Phương pháp thích hợp hơn là định nghĩa cho mỗi đối tượng được lưu trong một file.
Quy ước đặt tên cho các file ánh xạ là sử dụng tên của persistent class với phần mở rộng hbm.xml. Ví
dụ: File ánh xạ cho lớp Event có tên là Event.hbm.xml.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.manning.hq.ch03">
<class name="Event" table="events">
<id name="id" column="uid" type="long" unsaved-value="null">
<generator class="native"/>
</id>
<property name="name" type="string" length="100"/>
<property name="startDate" column="start_date"
type="date"/>
<property name="duration" type="integer"/>
<many-to-one name="location" column="location_id"
class="Location"/>
<set name="speakers">
<key column="event_id"/>
<one-to-many class="Speaker"/>
</set>
<set name="attendees">
<key column="event_id"/>
<one-to-many class="Attendee"/>
</set>
</class>
</hibernate-mapping>
File ánh xạ bắt đầu bằng hibernate-mapping element. Thuộc tính package thiết lập package mặc định
cho lớp. Thuộc tính set, bạn cần cung cấp tên của lớp persistent khác như: Speaker và Attendee.
Thẻ class bắt đầu định nghĩa ánh xạ cho lớp persistent xác định, thuộc tính table là tên của quan hệ
(relational) được sử dụng để lưu các đối tượng.
Element <id> mô tả khóa chính của persistent class - tự động được phát sinh. Thuộc tính name định
nghĩa các thuộc tính của persistent class sẽ được sử dụng để lưu giá trị của khóa chính.
Element <generate> được sử dụng để xác định tên của lớp phát sinh khóa chính cho record mới khi lưu
nó. Ở đây chúng ta sử dụng lớp native.
Sau đây là danh sách các generator phổ biến được sử dụng trong Hibernate:
• increment - phát sinh id (loại long, short hoặc int) là duy nhất chỉ khi không có tiến trình khác
chèn dữ liệu vào cùng bảng.
• identity - nó hỗ trợ cột id trong DB2, MySQL, MS SQL Server, Sybase và HypersonicSQL. Id
được trả về có loại long, short hoặc int.
• sequence - phát sinh sequence sử dụng một sequence trong DB2, PostgreSQL, Oracle, SAP DB,
McKoi hoặc Interbase. Id được trả về có loại long, short hoặc int.
• hilo - Bộ phát sinh hilo sử dụng thuật toán hilo để phát sinh id.
• native - Nó sẽ chọn id, sequence hoặc hilo phụ thuộc vào khả năng CSDL phía dưới.
Thuộc tính unsaved-value mô tả giá trị của thuộc tính id cho các thể hiện transient của lớp đó.
Mỗi element property này tương ứng với một thuộc tính trong đối tượng Event. Thuộc tính name chứa
tên thuộc tính, thuộc tính type xác định loại đối tượng của thuộc tính. Column được sử dụng để lưu giá
trị của thuộc tính.
Từ hình bạn có thể suy diễn rằng: nhiều thể hiện của Event kết hợp với một thể hiện của Location. Mặc
dù hình không hiển thị nó nhưng mối quan hệ này thì không phải hai chiều nghĩa là bạn có thể định vị
đến Location từ Event nhưng không thể ngược lại. Ở điểm này chúng ta sẽ biểu diễn file ánh xạ của lớp
Location như sau:
<?xml version="1.0"?>
<hibernate-mapping package="com.manning.hq.ch03">
<class name="Location" table="locations">
<id name="id" column="uid" type="long">
<generator class="native"/>
</id>
<property name="name" type="string"/>
<property name="address" type="string"/>
</class>
</hibernate-mapping>
Ánh xạ của lớp này thì tương tự như Event mặc dù nó không có thuộc tính nhiều và thiếu mối quan hệ
với các đối tượng persistent khác.
Đối với Event, element many-to-one định nghĩa tham chiếu giữa các đối tượng persistent. Ánh xạ mối
quan hệ many-to-one như sau:
Thuộc tính name cung cấp tên của thuộc tính trong đối tượng và thuộc tính column xác định column
được sử dụng để lưu khóa ngoại đến bảng location. Thuộc tính class cung cấp tên của lớp persistent cần
quan hệ.
Một câu hỏi phổ biến được đặt ra là: làm thế nào để tạo mối quan hệ many-to-one lazy - nghĩa là đối
tượng được kết hợp với nó sẽ không được rút trích khi đối tượng cha được rút trích. Các giải quyết là
sử dụng proxied objects.
1.5. Proxy:
Object proxy là cách tránh rút trích một đối tượng cho đến khi cần đến nó. Định nghĩa nó bằng 2 cách:
2. Sử dụng thuộc tính lazy = "true" là cách ngắn nhất để định nghĩa lớp persistent như proxy:
<class name="Location" lazy="true"...>...</class>
Thuộc tính lazy là true mặc định trong Hibernate 3. Cách sử dụng thể hiện proxied Location:
1.6. Collections:
File ánh xạ định nghĩa các collection của Speakers và Attendees. Collection được định nghĩa là set -
nghĩa là Hibernate quản lý các collection với ngữ cảnh là java.util.Set.
<set name="speakers">
<key column="event_id"/>
<one-to-many class="Speaker"/>
</set>
Định nghĩa này khai báo rằng lớp Event có một thuộc tính tên là speakers và nó là một Set chứa các thể
hiện của lớp Speaker. Lớp Event có thuộc tính tương ứng như sau:
Element key định nghĩa khóa ngoại từ bảng collection đến bảng cha. Trong trường hợp này, bảng
speakers có một column event_id tham chiếu đến column id trong bảng events. Element one-to-many
định nghĩa mối quan hệ với lớp Speaker.
1.7. Cascade:
Các thao tác lan truyền theo tầng trên một bảng (như delete) đến các bảng kết hợp. Giả sử, khi delete
Event, bạn cũng muốn delete các thể hiện Speaker kết hợp với Event. Thay vì code trong ứng dụng sẽ
thực hiện, Hibernate có thể quản lý nó thay cho bạn.
Element cascade được thêm vào many-to-one hoặc element collection. Ví dụ cấu hình sau sẽ hướng
dẫn Hibernate delete các Speaker con khi Event cha bị delete:
Khi thể hiện Event được load thì đối tượng Location kết hợp cũng sẽ được load bằng outer join. Nếu
muốn sử dụng câu lệnh select thì sẽ sử dụng như sau:
Đoạn mã sau sẽ load các file property và mapping được định nghĩa trong hibernate.cfg.xml và tạo
SessionFactory:
Phương thức configure() bảo Hibernate load file hibernate.cfg.xml. Nếu như nó không tồn tại thì chỉ
hibernate.properties được load từ classpath. Lớp Configuration cũng có thể load mapping document:
Nếu ứng dụng có 10 hoặc 100 mapping definitions. Bạn có thể tạo file JAR (ví dụ như
application.jar) chứa tất cả file class và mapping definitions. Sau đó cập nhật file hibernate.cfg.xml:
<mapping jar="application.jar"/>
Và bạn cũng có thể làm điều này với phương thức addJar của lớp Configuration:
Configuration.addJar(new java.io.File("application.jar"));
Cả 4 phương pháp này đều được sử dụng để xác định mapping definition phụ thuộc vào các yêu cầu
của project. Tuy nhiên mỗi khi bạn tạo SessionFactory từ thể hiện Configuration, thì bất kỳ file
mapping nào được thêm đến thể hiện của Configuration sẽ không ảnh hưởng trong SessionFactory.
Nghĩa là bạn không thể thêm một lớp persistent mới một cách tự động.
Bạn có thể sử dụng thể hiện của SessionFactory để tạo thể các thể hiện của Session:
Session session = factory.openSession();
Các thể hiện của lớp Session là giao tiếp chính của Hiberante framework. Chúng cho phép bạn
persist các đối tượng, truy vấn các đối tượng persistent và làm cho các đối tượng transient trở thành
persistent.
Gọi phương thức save(....) cho thể hiện Event sẽ gán cho nó một giá trị id được phát sinh và sau đó
là persist nó. Phương thức flush() ép các đối tượng persistent được giữ trong bộ nhớ được đồng bộ
xuống CSDL. Session không lập tức ghi liền xuống CSDL khi đối tượng được lưu. Thay vào đó,
Session sẽ sắp xếp các lần ghi để tăng tốc độ thực thi.
Nếu bạn muốn cập nhật một đối tượng đã được persistent, phương thức update() thì có sẵn. Sự khác
biệt của phương thức update() so với phương thức save() là nó không gán giá trị id cho đối tượng. Bởi
vì sự khác biệt này nên giao diện Session cung cấp phương thức saveOrUpdate() để xác định thao tác
đúng để thực thi trên đối tượng.
Hai dòng đầu tạo SessionFactory sau đó load file cấu hình từ classpath. Sau khi thể hiện Event được
tạo và rút trích, thể hiện Session được cung cấp bởi SessionFactory sẽ persist Event này. Session được
flush và close (đóng kết nối JDBC và dọn dẹp bên trong). Đó là tất cả những gì phải làm để persist các
đối tượng.
Code này lần đầu sẽ rút thể hiện Event, Session sẽ cache bên trong. Sau đó nó cập nhật tên Event, save
hoặc update thể hiện Event, rút trích cùng thể hiện Event (được lưu trong Session cache), update
duration của Event và save hoặc update thể hiện Event. Cuối cùng flush Session - tất cả các lần cập
nhật được kết hợp vào chỉ một cập nhật khi bạn flush Session.
Một vấn đề phổ biến đối với developer mới là run hai thể hiện của cùng một đối tượng trong cùng một
thể hiện Session, kết quả là NonUniqueObjectException. Code sau sẽ phát sinh exception này:
Code này mở thể hiện Session, load thể hiện Event với id xác định, tạo thể hiện Event thứ hai với cùng
id và sau đó cố gắng save thể hiện Event thứ hai, kết quả là NonUniqueObjectException.
Bất kỳ thời điểm nào, nếu đối tượng đi qua thể hiện Session, nó sẽ được thêm vào cache của Session.
Để xem đối tượng được chứa trong cache, hãy gọi phương thức Session.contains(). Các đối tượng có
thể bị đẩy ra khỏi cache bằng cách gọi phương thức Session.evict(). Chúng ta hãy xem lại code trước,
lần này đẩy thể hiện Event thứ nhất ra khỏi cache:
Code này đầu tiên sẽ mở thể hiện Session và load thể hiện Event với id xác định trước. Kế tiếp nó xác
định xem đối tượng này có được chứa trong cache của Session hay chưa và đẩy nó ra nếu cần thiết.
Code sau đó tạo thể hiện Event thứ hai với cùng id và sau nó thành công.
Nếu bạn muốn hủy tất cả các đối tượng từ Session cache, bạn có thể gọi chỉ một phương thức là
Session.clear().
Nếu bạn chạy một ứng dụng hông hỗ trợ connection pool thì nên sử dụng service connecton pool mà
Hibernate hỗ trợ: C3PO, Apache’s DBCP library, và Proxool.
Khi chọn một service connection pool, bạn phải cấu hình nó cho môi trường của bạn. Hibernate hỗ
trợ cấu hình connection pool trong file hibernate.cfg.xml. Thuộc tính connection.provider_class thiết
lập cài đặt pooling như sau:
<property name="connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
Mỗi khi provider class được thiết lập, các thuộc tính khác của pooling service cũng phải được cấu
hình:
<property name="c3p0.minPoolSize">
5
</property>
...
<property name="c3p0.timeout">
1000
</property>
1.15. Transaction:
Transaction nhóm nhiều thao tác vào trong một đơn vị làm việc. Nếu bất kỳ thao tác trong nhóm thất
bại thì tất cả các thao tác trước đều bị roll back và đơn vị làm việc đó sẽ dừng lại.
Hibernate có một lớp Transaction được truy cập từ giao tiếp Session như sau:
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Event event = new Event();
// ... populate the Event instance
session.saveOrUpdate(event);
tx.commit();
Trong ví dụ này, factory là một thể hiện SessionFactory được khởi tạo. Code này tạo một thể hiện
của lớp org.hibernate.Transaction và sau đó ủy nhiệm thể hiện của Transaction này.
Ghi chú: bạn không cần gọi session.flush(). Ủy nhiệm transaction sẽ tự động flush đối tượng
Session. Thể hiện Event được persist vào CSDL khi transaction được ủy nhiệm.
package com.manning.hq.ch04;
import java.io.Serializable;
import java.util.Date;
import com.manning.hq.ch04.Location;
public class Event implements Serializable {
private Long id;
private int duration;
private String name;
private Date startDate;
private Location location;
public Event() { }
public Event(String name) {
this.name = name;
}
public Long getId() { return id; }
public void setId(Long id) {
this.id = id;
}
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public Date getStartDate() { return startDate; }
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public int getDuration() { return duration; }
public void setDuration(int duration) {
this.duration = duration;
}
public Location getLocation() { return location; }
public void setLocation(Location location) {
this.location = location;
}
}
package com.manning.hq.ch04;
import java.io.Serializable;
public class Location implements Serializable {
private Long id;
private String name;
private String address;
public Location() { }
public Location(String name) {
this.name = name;
}
public Long getId() { return id; }
public void setId(Long id) {
this.id = id;
}
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public String getAddress() { return address; }
public void setAddress(String address) {
this.address = address;
}
}
Như bạn thấy cả hai lớp này đều theo đặc tả JavaBean. Ghi chú là lớp Event có một trường location
để liên kết nó với đối tượng Location.
Mỗi lớp này sẽ cần một file ánh xạ tương ứng, trong trường hợp này là Event.hbm.xml và
Location.hbm.xml để định nghĩa các trường persistent và mối quan hệ giữa hai file này. Đặt các file
này cùng thư mục với Event.java và Location.java. Sau đây là hai file ánh xạ này:
Location.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.manning.hq.ch04">
<class name="Location" table="locations">
<id name="id" column="uid" type="long">
<generator class="native"/>
</id>
<property name="name" type="string"/>
<property name="address" type="string"/>
</class>
</hibernate-mapping>
session.save(event);
// session.save(location);
=> tiết kiệm được một dòng code :D.
2.2. Component:
Component hông phải là một thực thể, nó giống như một đối tượng được chứa trong một đối tượng
cha khác. Nó hông có id và chỉ tồn tại khi thực thể cha tồn tại.Component cho phép bạn nhóm một
vài cột vào trong một đối tượng.
Ví dụ:
Chúng ta có một trường address trong Location. Do thiết kế hông tốt nên chúng ta sẽ chia nhỏ địa
chỉ thành 4 cột: street, city, state và zip code. Và khi đó đối tượng Location sẽ như thế này:
Cách thiết kế này làm việc được nhưng hông được tốt cho lắm, chúng ta sẽ rút trích một vài trường
cho vào một đối tượng Address và để Hibernate điều khiển nó như một component:
Và điều cuối cùng cần làm là ánh xạ một số cột từ bảng location cho đối tượng Address:
<hibernate-mapping package="com.manning.hq.ch04">
<class name="Location" table="locations">
<id name="id" column="uid" type="long">
<generator class="native"/>
</id>
<property name="name" type="string"/>
<component name="address" class="Address" >
<property name="streetAddress"
column="street_address" type="string"/>
<property name="city" type="string"/>
<property name="state" type="string"/>
<property name="zipCode"
column="zip_code" type="string"/>
</component>
</class>
</hibernate-mapping>
Bây giờ bạn có thể chèn dữ liệu vào đối tượng Location như sau:
3. Collection in Hibernate:
3.1. Mapping Collection:
3.1.1 Quan hệ 1 - nhiều:
Quan hệ này tạo liên kết giữa một thể hiện của lớp cha với nhiều thể hiện của lớp con.
Ví dụ: Chúng ta sẽ định nghĩa một set attendees tương tự one-to-many - nghĩa là một thể hiện Event
sẽ kết hợp với nhiều thể hiện Attendee.
<hibernate-mapping package="com.manning.hq">
<class name="Event" table="events">
…
<set name="speakers">
<key column="event_id"/>
<one-to-many class="Speaker"/>
</set>
<set name="attendees">
<key column="event_id"/>
<one-to-many class="Attendee"/>
</set>
…
</class>
</hibernate-mapping>
=> element <key> với thuộc tính column - tên của cột lưu khóa ngoại của lớp đang chứa.
Tại sao có lazy collection: Một collection các đối tượng có thể chứa hàng trăm hoặc hàng ngàn các đối
tượng và ứng dụng có thể không cần truy cập collection ngay lập tức hoặc tất cả. Load hàng trăm đối
tượng không có lý do sẽ làm giảm tốc độ của ứng dụng. Tốt hơn nên rút trích các persistent collection
chỉ khi nó cần dùng.
Persistent collection được lazy mặc định bởi Hibernate 3. Để làm cho collection hông lazy, bạn phải
khai báo rõ ràng như sau: lazy="false" trong mapping file:
Ví dụ:
Trả về tất cả các Attendees của Event theo thứ tự của last name, mapping definition của chúng ta sẽ
như sau:
<hibernate-mapping package="com.manning.hq">
<class name="Attendee" table="attendees">
…
<many-to-one column="event_id" class="Event"/>
…
</class>
</hibernate-mapping>
Thêm thuộc tính inverse="true" trong file ánh xạ của Event như sau:
Khi bạn cố gắng lưu thể hiện này, bạn sẽ gặp lỗi bởi vì Event tham chiếu đến thể hiện transient của lớp
Speaker. Để khắc phục cần cập nhật mapping file như sau:
Thêm thuộc tính cascade xác định thao tác save-update để khi thực hiện đối tượng cha thì nó sẽ ảnh
hưởng đến Speaker. Cách này Hibernate sẽ điều khiển việc tạo Speaker chính xác và lưu chúng vào
CSDL.
Ví dụ:
from Event => trả về tất cả các thể hiện của Event trong CSDL, cùng các đối tượng có quan hệ và non-
lazy collection.
4.1.1. session.find():
Trong Hibernate2, giao tiếp Session có 3 phương thức overload find(), 2 phương thức hỗ trợ binding
tham số. Mỗi phương thức trả về một java.util.List với kết quả của câu truy vấn. Ví dụ, chúng ta thực
thi câu truy vấn sau:
Ví dụ:
Chúng ta hãy thực thi câu truy vấn trước sử dụng giao tiếp Query:
Query q = session.createQuery("from Event");
List results = q.list();
Nếu bạn muốn thiết lập giới hạn số đối tượng Event được trả về, thì bạn sẽ phải thiết lập thuộc tính
maxResults:
Query q = session.createQuery("from Event");
q.setMaxResults(15);
List results = q.list();
a) Posistion parameter:
Thì tương tự như Prepared-Statement. Chỉ có sự khác biệt là vị trí index bắt đầu từ 0 thay vì 1.
Giả sử bạn muốn trả về tất cả thể hiện Event có tên được xác định trước. Sử dụng positional
parameter như sau:
Query q = session.createQuery("from Event where name = ? ");
q.setParameter(0, "Opening Plenary");
List results = q.list();
Lưu ý rằng bạn không cần thiết lập loại tham số, đối tượng Query sẽ cố gắng xác định loại của nó.
Nó cũng có thể thiết lập tham số có loại xác định sử dụng lớp org.hibernate.Hibernate:
q.setParameter(0, "Opening Plenary", Hibernate.STRING);
b) Named parameters:
Cách dễ dàng nhất để giải thích named parameters là sử dụng một ví dụ cụ thể:
from Event where name = :name
Thay vì ? để ghi nhận một tham số, bạn có thể sử dụng :name để rút trích câu truy vấn:
Query q = session.createQuery("from Event where name = :name");
q.setParameter("name", "Opening Plenary");
List results = q.list();
Với named parameter bạn không cần biết vị trí index của mỗi tham số.
c) Named queries:
Nó được nhúng trong mapping definition. Bạn phải đặt tất cả các câu truy vấn vào trong cùng file
với đối tượng cần được truy vấn. Named queries được đặt ở dưới cùng của file mapping definition:
<query name="Event.byName">
<![CDATA[from Event where name=?]]>
</query>
Có 4 loại joins:
• left join - lấy tất cả các thể hiện bên trái của mệnh đề join, nếu đối tượng bên trái của join
không có đối tượng phù hợp bên phải thì nó vẫn trả về.
• right join thì tương tự như left nhưng ở bên phải.
• full join - trả về các đối tượng hai bên của mệnh đề join bất chấp đối tượng có phù hợp bên kia
hay không.
• inner join fetch - rút trích các đối tượng có quan hệ hoặc collection các đối tượng của outer-
join hoặc thuộc tính lazy trong mối quan hệ.
from Event e inner join fetch e.speakers => trả về các đối tượng của Event với collection các speaker.
from Event e join e.location l where l.name = :name => join thể hiện của Location với Event để cho
phép truy vấn trên các thuộc tính của Location.
Ví dụ:
select count(e) from Event e => trả về số đối tượng Event được persist trong CSDL.
4.5. Criteria:
Criteria API cung cấp phương pháp khác để truy vấn các đối tượng persistent. Nó cho phép xâu dựng
các câu truy vấn động. Criteria được sử dụng khi có nhiều tham số cho chức năng search.
Ví dụ:
Bạn có màn hình search nâng cao, cho phép người dùng chọn nhiều trường để tìm kiếm.