(http://my.opera.com/mattroiden3012/blog/tong-quan-hibernate-framework)
Có lẽ bạn đã nghe nói nhiều về Hibernate framework? Thế Hibernate framework là gì? Hy vọng mình và bạn sẽ có trả lời câu hỏi đó khi đọc xong những dòng bên dưới.
Trước khi tìm hiểu Hibernate là gì, chúng ta cần chuẩn bị một số kiến thức để làm nền tảng. Đầu tiên, chúng ta cần tìm hiểu "framework" là gì? Framework ngày nay được "lạm dụng" rất nhiều. Nhiều người hay gán một vài thứ là "framework" nhưng gán gọi như vậy có đúng không lại là một chuyện khác. Theo cộng đồng wikipedia, từ framework dùng trong phát triển phần mềm là một khái niệm dùng để chỉ những "cấu trúc hỗ trợ được định nghĩa" mà trong đó những dự án phần mềm khác có thể được sắp xếp vào đó và phát triển. Thông thường, một framework bao gồm những program hỗ trợ, code libs và một ngôn ngữ scripting nằm giữa các chương trình phần mềm khác để giúp phát triển và gắn những thành phần khác nhau trong dự án phần mềm lại với nhau.
Tiếp theo, chúng ta cần tìm hiểu về "persistence layer". Từ này tạm thời mình chưa thể dịch sang tiếng Việt được mà chỉ giải thích để bạn hiểu nó là cái gì thôi. Như bạn đã biết, kiến trúc ứng dụng dụng phần mềm có nhiều loại. Có loại chỉ chạy trên một máy là đủ. Có chương trình muốn chạy được phải kết nối sang một máy khác (client-server). Một máy đóng vai trò như là người yêu cầu (client) và máy khác đóng vai trò kẻ phục vụ (server). Người ta sử dụng thuật ngữ "tier" để chỉ mỗi loại máy có vai trò khác nhau đó. Tier client để chỉ các máy đóng vai trò client và tier server để chỉ các máy đóng vai trò server. Và loại ứng dụng client-server là ứng dụng 2-tier (vì chỉ có 2 tier thôi). Tương tự như vậy theo sự phát triển như vũ bão của công nghệ phần cứng và phần mềm cộng với nhu cầu của các người dùng, doanh nghiệp và xã hội ngày càng lớn, chúng ta thấy có các ứng dụng 3-tier và n-tier để khắc phục nhược điểm của ứng dụng 2-tier và nhằm tăng sức mạnh xử lý cho ứng dụng. "Layer" là một khái niệm khác với "tier". Và chúng ta đừng lầm lẫn giữa "tier" và "layer". Tier thường gắn với phần cứng máy tính (về mặt physically) còn "layer" thì dính với vấn đề cách thức tổ chức bên trong của ứng dụng. Việc phân chia tier là "trong suốt" (transparent) đối với ứng dụng xét về mặt luận lý (logically). Điều này có nghĩa là khi chúng ta phát triển một ứng dụng, chúng ta không bận tâm đến các thành phần (component) sẽ triển khai (deploy) ra sao mà chỉ chú ý là chúng ta sẽ tổ chức ứng dụng thành những layer như thế nào. Ví dụ, một ứng dụng có thể chia làm 3 phần như sau: phần giao diện người dùng (UI layer), phần xử lý nghiệp vụ (business layer) và phần chứa dữ liệu (data layer). Cụ thể ra, business layer sẽ có thể chia nhỏ thành 2 layer con là business logic layer (chỉ quan tâm đến ý nghĩa của các nghiệp vụ, các tính toán mang nhằm thoả mãn yêu cầu của người dùng) và persitence layer. Persistence layer chịu trách nhiệm giao tiếp với data layer (thường là một hệ quản trị cơ sở dữ liệu quan hệ - Relational DBMS). Persistence layer sẽ đảm nhiệm các nhiệm vụ mở kết nối, truy xuất và lưu trữ dữ liệu vào các Relational DBMS.
Việc phân chia như vậy có lợi ích là công việc sẽ được tách bạch ra. Người nào lo thiết kế và xử lý UI thì chỉ việc chú tâm vào công việc đó. Người lo business layer thì chỉ cần tập trung vào thiết kế và phát triển làm sao thoả mãn các requirement của khách hàng mà không phải chú tâm đến các khía cạnh hiện thực bên dưới thông thường liên quan đến technical issues. Còn người lo persistence layer thì chỉ việc chú trọng đến các khía cạnh hiện thực và giải quyết các technical issues mà thôi. Cũng như sẽ có những DBA (DB Administrators) lo việc cài đặt và tạo các objects trong các relational database.
Như vậy, bạn đã hiểu ứng dụng được chia một cách logically thành các "layer" và bạn cũng hiểu được là persistence layer là một layer có nhiệm vụ kết nối Relational DBMSs và truy xuất, thao tác trên dữ liệu đã được lưu trữ cũng như lưu trữ dữ liệu mới vào chúng. Hibernate framework là một framework cho persistence layer. Và bạn có thể thấy rằng nhờ có Hibernate framework mà giờ đây khi bạn phát triển một ứng dụng bạn chỉ còn chú tâm vào những layer khác mà không phải bận tâm nhiều về persistence layer nữa. Tương tự như vậy nếu bạn có một UI framework, bạn sẽ không phải bận tâm nhiều về UI layer nữa. Và xét đến cùng, việc bạn quan tâm duy nhất là business logic layer của bạn có đáp ứng yêu cầu của khách hàng không hay thôi.
Và đây là thông tin về Hibernate framework từ website chính thức của Hibernate: Hibernate là một dịch vụ lưu trữ và truy vấn dữ liệu quan hệ mạnh mẽ và nhanh. Hibernate giúp bạn phát triển các class dùng để lưu trữ dữ liệu theo cách thức rất là hướng đối tượng: association, inheritance, polymorphism, composition và collections. Hibernate cho phép bạn thực hiện các câu truy vấn dữ liệu bằng cách sử dụng ngôn ngữ SQL mở rộng của Hibernate (HQL) hoặc là ngôn ngữ SQL nguyên thuỷ cũng như là sử dụng các API.
Không giống như các persistence layer khác, Hibernate không ẩn đi sức mạnh của ngôn ngữ SQL khỏi bạn mà Hibernate còn đảm bảo cho bạn việc bạn đầu tư vào công nghệ và tri thức cơ sở dữ liệu quan hệ là luôn luôn chính xác. Và điều quan trọng hơn nữa là Hibernate được license theo LGPL (Lesser GNU Public License). Theo đó, bạn có thể thoải mái sử dụng Hibernate trong các dự án open source hoặc các dự án thương mại (commercial).
Hibernate là một dự án open source chuyên nghiệp và là một thành phần cốt tuỷ của bộ sản phẩm JBoss Enterprise Middleware System (JEMS). JBoss, như chúng ta đã biết là một đơn vị của Red Hat, chuyên cung cấp các dịch vụ 24x7 về hỗ trợ chuyên nghiệp, tư vấn và huyấn luyện sẵn sàng hỗ trợ bạn trong việc dùng Hibernate.
Các thành phần của Hibernate project:
* Hibernate Core: Cung cấp các chức năng cơ bản của một persistence layer cho các ứng dụng Java với các APIs và hỗ trợ XML mapping metadata.
* Hibernate Annotations: Các map class với JDK 5.0 annotations, bao gồm Hibernate Validator.
* Hibernate EntityManager: Sử dụng EJB 3.0 EntityManager API trong JSE hoặc với bất kỳ JEE server nào.
* Hibernate Tools: Các tool tích hợp với Eclipse và Ant dùng cho việc sinh ra các persistence object từ một schema có sẵn trong database (reverse-engineering) và từ các file hbm sinh ra các class java để hiện thực các persistence object, rồi Hibernate tự tạo các object trong database (forward-engineering).
* NHibernate: Hibernate cho .Net framework.
* JBoss Seam: Một Java EE 5.0 framework cho phát triển các ứng dụng JSF, Ajax và EJB 3.0 với sự hỗ trợ của Hibernate. Seam hiện rất mới và tỏ ra rất mạnh để phát triển các ứng dụng Web 2.0. Nó tích hợp đầy đủ tất cả các công nghệ "hot" nhất hiện nay.
Phát triển một ứng dụng doanh nghiệp bao gồm rất nhiều các nỗ lực để lưu trữ các đối tượng bussiness object vào Database, Thông thường, 70% nỗ lực để phát triển ứng dụng thì viết code cho duy trì kết nối database và lưu các entities vào database. Hầu hết các ứng dụng doanh nghiệp đã phát triển sử dụng công nghệ Object Oriented.
Buiness logic bên trong luồng ứng dụng trong hình thức của object thay vì các thông điệp văn bản và nó được sử dụng ở giai đoạn lập trình cấu trúc ở đó chúng ta thiết lập một loạt biến để chạy hay chỉ ra trạng thái của entity.
Ngày nay công nghệ hướng đối tượng ra đời giải quyết những bài toán phức tạp trong cho business flow. Chỉ cần nói lưu objects vào database là một giai đoạn ở đó các đối tượng chuyển ngược trở lại văn bản text và lưu vào database. Để hiểu nhiều hơn, xem đoạn mã dưới đây.
Tạo một kết nối.
Class.forName(driverClass); java.sql.Connection connection = java.sql.DriverManager.getConnection(databaseUrl,databaseUser,databasePassword);
Giả sử chúng ta có một đối tượng của lớp User, và chúng ta cần lưu trữ object này xuống database. Xem hàm sau:
private void saveUser(User user) throws SQLException { PreparedStatement pstmt = connection.prepareStatement("insert into users values(?,?,?)"); pstmt.setInt(1,user.getId()); pstmt.setString(2,user.getName()); pstmt.setString(3,user.getEmail()); pstmt.setString(4,user.getAddress()); pstmt.execute(); }
Vấn đề của đoạn mã này là là nó rải rác khắp nnơi trong ứng dụng ảnh hưởng đến khả năng bảo trì ứng dụng . Có rất nhiều vấn đề với các tiếp cận kiểu này:
• Mã thì rải rác khắp nơi đến những nơi không quản lý nổi.
• Nếu thiết kế bị thay đổi sau khi phát triển ứng dụng, phải trả giá rất đắt để nhận ra những nơi cần phải thay đổi.
• Khó tìm và fix bug.
• Quản lý các kết nối database là một nhiệm vụ cực kỳ khó khăn vì mã SQL nằm tùm lum, kết nối database cũng vậy.
• Quản lý transaction là một nhiệm vụ phức tạp.
Vì những vấn đề trên, sửa lỗi là một giai đoạn của quy trình phát triển phần mềm mà làm cho ứng dụng trở nên cực kỳ đắt đỏ thậm chí sau khi đã hoàn thành.
Cần thiết phải có một cơ chế tách biệt mã persistent database và viết nó một cách hiệu quả để khi có một thay đổi trong thiết kế database, nó có thể dễ dàng cài đặt với niềm tìm không có nơi nào còn bug.
Thuận lợi của cơ sỡ dữ liệu quan hệ:
• Tìm kiếm và sắp xếp nhanh.
• làm việc được với dữ liệu lớn.
• làm việc trên nhóm dữ liệu.
• Joining, aggregating.
• Chia sẽ nhiều người dùng và nhiều vùng.
• Giải quyết tương tranh (Transaction)
• Hỗ trợ cho nhiều ứng dụng.
• Bảo đảm toàn vẹn.
• Ràng buộc nhiều cấp độ.
• Tách biệt giao tác.
Vấn đề của cơ sở dữ liệu quan hệ.
Mô hình dữ liệu không hỗ trợ tính đa hình.
Business logic trong server ứng dụng có thể trùng lặp tại database là các Store Procedure.
không gắn liền với các đối tượng ngoài đời thực.
Tốn code để gắn Java Object với database objects.
====================================
Cách Sử Dụng HIBERNATE
http://fly2universe.wordpress.com/2010/06/11/s%E1%BB%AD-d%E1%BB%A5ng-hibernate-trong-java-swing-application/
====================================
1.Cấu hình:
Hibernate được cấu hình theo hai bước:
* Cấu hình service bao gồm: tham số kết nối CSDL, caching và tập các lớp persistent.
* Cung cấp cho Hibernate các thông tin về các lớp được persist.
Để 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.
1.1. Cấu hình cơ bản:
Hibernate cung cấp 2 phương pháp cấu hình: file properties theo chuẩn của Java được gọi là hibernate.properties và file có định dạng XML gọi là hibernate.cfg.xml. Chúng ta sẽ sử dụng file cấu hình XML để cấu hình các service của Hibernate. Nếu cả hai file hibernate.properties và hibernate.cfg.xml được tìm thấy trong classpath của ứng dụng thì hibernate.cfg.xml sẽ override lên các thiết lập được tìm thấy trong hibernate.properties.
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.
a) Sử dụng kết nối JDBC được quản lý bởi Hibernate:
Sau đây là file cấu hình mẫu sử dụng loại kết nối JDBC được quản lý bởi Hibernate:
<?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.
b) Sử dụng JNDI DataSource:
Để sử dụng Hibernate với kết nối CSDL được cung cấp bởi JNDI DataSource, bạn cần thay đổi một vài chỗ trong file cấu hình như sau:
<?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.
1.2. Tạo định nghĩa ánh xạ:
Các định nghĩa ánh xạ được gọi là mapping document, được sử dụng để cung cấp cho Hibernate các thông tin để lưu trữ các đối tượng đến CSDL quan hệ. Các file ánh xạ cung cấp các đặc tính như tạo lược đồ CSDL từ tập hợp các file ánh xạ.
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 đó.
1.3. Các thuộc tính:
Element property của đối tượng Event thì tương tự như element id:
<property name="name" type="string" length="100"/>
<property name="startDate" column="start_date" type="date"/>
<property name="duration" type="integer"/>
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.
1.4. Element many-to-one:
Định nghĩa mối quan hệ với lớp Location. Mối quan hệ nhiều - một sử dụng khóa ngoại để duy trì mối quan hệ giữa hai lớp persistent.
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:
<many-to-one name="location" column="location_id" class="Location"/>
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ệ.
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:
1. Thêm thuộc tính proxy vào element class:
<class name="Location" proxy="com.manning.hq.ch03.Location"...>
...
</class>
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:
Session session = factory.openSession();
Event ev = (Event) session.load(Event.class, myEventId);
Location loc = ev.getLocation();
String name = loc.getName();
session.close();
Trả về thể hiện của Location là proxy. Hibernate lấy thể hiện Location khi getName() được gọi.
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:
public class Event {
private Set speakers;
...
public void setSpeakers(Set speakers) {
This.speakers = speakers;
}
public Set getSpeakers() {
return this.speakers;
}
...
}
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.
Ngoài Set Hibernate còn hỗ trợ Map và List.
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.
Các loại cascade: all, save-update, delete, delete-orphan.
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:
<set name="speakers" cascade="delete">
<key column="event_id"/>
<one-to-many class="Speaker"/>
</set>
1.8. Duyệt các đối tượng kết hợp:
Bạn có thể rút trích các đối tượng kết hợp sử dụng outer join hoặc bằng câu lệnh SELECT. Thuộc tính fetch cho phép bạn xác định các phương thức để sử dụng:
<many-to-one name="location" class="Location" fetch="join"/>
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:
<many-to-one name="location" class="Location" fetch="select"/>
1.9. Xây dựng SessionFactory:
Giao tiếp SessionFactory của Hibernate cung cấp các thể hiện của lớp Session để biểu diễn các kết nối đến CSDL. Thể hiện của SessionFactory là thread-safe và chia sẽ suốt ứng dụng. Các thể hiện Session không phải là thread-safe và chỉ nên được sử dụng cho một transaction hoặc đơn vị làm vị trong ứng dụng.
1.9.1. Cấu hình SessionFactory:
a) Lớp Configuration:
Lớp này là sự mở đầu runtime của Hibernate. Nó được sử dụng để load các file ánh xạ và tạo SessionFactory cho các file ánh xạ này. Mỗi lần 2 chức năng này hoàn tất, lớp Configuration có bị vứt bỏ. Tạo một thể hiện của Configuration và Session thì đơn giản nhưng bạn có một vài tùy chọn. Có 3 cách để tạo và khởi tạo đối tượng Configuration.
Đoạn mã sau sẽ load các file property và mapping được định nghĩa trong hibernate.cfg.xml và tạo SessionFactory:
Configuration cfg = new Configuration();
SessionFactory factory = cfg.configure().buildSessionFactory();
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:
Configuration cfg = new Configuration();
cfg.addFile("com/manning/hq/ch03/Event.hbm.xml");
Một phương pháp khác để Hibernate load mapping document là dựa vào lớp persistent. Ví dụ, code sau sẽ khiến cho Hibernate tìm file có tên là com/manning/hq/Event.hbm.xml trong classpath và load các lớp kết hợp:
Configuration cfg = new Configuration();
cfg.addClass(com.manning.hq.ch03.Event.class);
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.
1. 10. Persistent các đối tượng:
Persist đối tượng transient (tạm thời) với Hibernate thì đơn giản - lưu nó với thể hiện Session:
Event event = new Event();
// populate the event
Session session = factory.openSession();
session.save(event);
session.flush();
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.
Sau đây là đoạn mã để persist thể hiện Event:
Configuration cfg = new Configuration();
SessionFactory factory = cfg.buildSessionFactory();
Event event = new Event();
// populate the Event instance
Session session = factory.openSession();
session.saveOrUpdate(event);
session.flush();
session.close();
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.
1.11. Rút trích đối tượng:
Event event = (Event) session.load(Event.class, eventId);
=> trả về thể hiện của Event với id bằng với eventId.
Query query = session.createQuery("from Event");
List events = query.list();
=> trả về toàn bộ các đối tượng từ CSDL.
Sử dụng PreparedStatement cho câu truy vấn:
Query query = session.createQuery("from Event where name = ?",
"Opening Presentation");
query.setParameter(0, "Opening Presentation", Hibernate.STRING);
List events = query.list();
1.12. Ánh xạ kế thừa:
Giả sử bạn có Event với hai lớp con ConferenceEvent và NetworkingEvent. Định nghĩa ánh xạ như sau:
<class name="Event" table="events" discriminator-value="EVENT">
<id name="id" type="long">
<generator class="native"/>
</id>
<discriminator column="event_type" type="string" length="15"/>
...
<subclass name="ConferenceEvent" discriminator-value="CONF_EVENT">
<property name="numberOfSeats" column="num_seats"/>
...
</subclass>
<subclass name="NetworkingEvent" discriminator-value="NET_EVENT">
<property name="foodProvided" column="food_provided"/>
...
</subclass>
</class>
1.13. Session cache:
Một cách dễ dàng để cải tiến tốc độ thực thi là cache các đối tượng. Bằng cách caching trong bộ nhớ, Hibernate sẽ tránh chi phí rút trích chúng từ database mỗi lần được yêu cầu. Cache cũng ảnh hưởng đến việc lưu và cập nhật các đối tượng:
Session session = factory.openSession();
Event e = (Event) session.load(Event.class, myEventId);
e.setName("New Event Name");
session.saveOrUpdate(e);
// later, with the same Session instance
Event e = (Event) session.load(Event.class, myEventId);
e.setDuration(180);
session.saveOrUpdate(e);
session.flush();
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:
Session session = factory.openSession();
Event firstEvent = (Event) session.load(Event.class, myEventId);
// ... perform some operation on firstEvent
Event secondEvent = new Event();
secondEvent.setId(myEventId);
session.save(secondEvent);
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:
Session session = factory.openSession();
Event firstEvent = (Event) session.load(Event.class, myEventId);
// ... perform some operation on firstEvent
if (session.contains(firstEvent)) {
session.evict(firstEvent);
}
Event secondEvent = new Event();
secondEvent.setId(myEventId);
session.save(secondEvent);
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().
1.14. Cấu hình nâng cao:
a) Connection pool:
Connection pool là cách phổ biến để cải tiến tốc độ thực thi của ứng dụng. Thay vì mở từng connection đến CSDL cho mỗi yêu cầu, connection pool sẽ duy trì một tập hợp các connection được mở để tái sử dụng lại. Application server thường cung cấp connection pool riêng sử dụng JNDI DataSource.
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.
2. Association và Component trong Hibernate:
2.1. Association:
Giả sử trong ứng dụng của bạn, mỗi Event được tổ chức ở chỉ một Location. Cách mà biểu diễn điều này trong Java là đối tượng Event có một trường Location. Khi bạn rút trích Event, bạn muốn cả Location nữa. Vì thế bạn phải liên kết Event và Location với nhau sử dụng quan hệ many-to-one.
Định nghĩa các lớp Event và Location như sau:
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>
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.ch04">
<class name="Event" table="events">
<id name="id" column="uid" type="long">
<generator class="native"/>
</id>
<property name="name" type="string"/>
<property name="startDate" column="start_date"
type="date"/>
<property name="duration" type="integer"/>
<many-to-one name="location" column="location_id" class="Location" />
</class>
</hibernate-mapping>
2.1.1. Location cascading:
Cascading có nghĩa là khi bạn save, update, delete một đối tượng, thì các mối quan hệ với nó cũng chịu ảnh hưởng. Trong trường hợp này bạn muốn Location được lưu khi bạn lưu hoặc cập nhật Event. Thêm một thuộc tính mới cho element <many-to-one> trong Event.hbm.xml file như sau:
<many-to-one name="location" column="location_id" class="Location" cascade="save-update" />
Khi đó bạn thể sử dụng:
session.save(event);
// session.save(location);
=> tiết kiệm được một dòng code .
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:
public class Location implements Serializable {
private Long id;
private String name;
private String streetAddress;
private String city;
private String state;
private String zipCode;
// getters and setter omitted
}
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:
public class Location implements Serializable{
private Long id;
private String name;
private Address address = new Address();
// Other getter/setters omitted
public Address getAddress() { return address; }
public void setAddress(Address address) {
this.address = address;
}
}
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:
Location location = new Location();
location.setName("Hilton Convention Center");
location.getAddress().setStreetAddress("950 North Stafford St.");
location.getAddress().setCity("Arlington");
location.getAddress().setState("VA");
location.getAddress().setZipCode("22204");
Event event = new Event();
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>
Lớp Event tương ứng như sau:
public class Event {
private Set speakers;
private Set attendees;
public void setSpeakers(Set speakers) {
this.speakers = speakers;
}
public Set getSpeakers() {
return this.speakers;
}
public void setAttendees(Set attendees) {
this.attendees = attendees;
}
public Set getAttendees () {
return this.attendees;
}
…
}
=> 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.
3.1.2. Quan hệ nhiều-nhiều:
Quan hệ này khá hấp dẫn hơn quan hệ 1-nhiều. Thay vì các bảng liên kết với nhau thông qua khóa ngoại, thì mối quan hệ nhiều-nhiều yêu cầu một bảng collection lưu tập hợp các đối tượng tham chiếu. Giả sử Attendees có thể tham dự nhiều hơn một Event. Ánh xạ many-to-many cho tập hợp các Attendees như sau:
<set name="attendees" table="event_attendees">
<key column="event_id"/>
<many-to-many column="attendee_id" class="Attendee"/>
</set>
3.2. Lazy collection:
Lazy collection sẽ được rút trích theo yêu cầu. Theo yêu cầu nghĩa là tập hợp các thực thể hoặc các giá trị được rút trích chỉ khi ứng dụng truy cập collection.
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.
Rút trích lazy collection (cụ thể là attendees) như sau:
Session session = factory.openSession();
Event event = session.get(Event.class, eventId);
Set attendees = event.getAttendees();
session.close();
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:
<set name="attendees" lazy="false">
<key column="event_id"/>
<one-to-many class="Attendee"/>
</set>
3.3 Sorted collection:
Một yêu cầu phổ biến khi giải quyết với collection là sắp xếp chúng theo một vài tiêu chí. Nếu bạn muốn collection trả về theo một thứ tự, bạn có thể thêm thuộc tính order-by vào element <set>.
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:
<set name="attendees" order-by="last_name">
<key column="event_id"/>
<one-to-many class="Attendee"/>
</set>
3.4. Ánh xạ quan hệ hai chiều:
Lớp Event cho phép bạn định vị từ thể hiện Event cha đến thể hiện Attendee con. Tuy nhiên giả sử bạn muốn tại mối quan hệ hai chiều, cho phép một Attendee định vị đến Event cha của nó. Để thực hiện được điều này, đầu tiên bạn phải xác định thuộc tính Event trong lớp Attendee và cung cấp định nghĩa many-to-one trong file ánh xạ Attendee. Kế tiếp định nghĩa inverse trong Event - thiết lập thuộc tính inverse="true" để thông báo cho Hibernate runtime mối quan hệ hai chiều này.
Các bước được thực hiện như sau:
public class Attendee {
private Event event;
…
public void setEvent(Event event) {
this.event = event;
}
public Event getEvent() {
return this.event;
}
}
File ánh xạ của Attendee:
<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:
<set name="attendees" inverse="true">
<key column="event_id"/>
<one-to-many class="Attendee"/>
</set>
3.5. Cascading collecion:
Giả sử bạn tạo một đối tượng mới Event, và thêm speakers vào nó:
Event event = new Event();
Set speakers = new HashSet();
speakers.add(new Speaker());
speakers.add(new Speaker());
speakers.add(new Speaker());
event.setSpeakers(speakers);
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.
4. Hibernate Query Language:
HQL (Hibernate Query Language) cung cấp một mức trừu tượng giữa ứng dụng và CSDL. SQL được thiết kế để làm việc với CSDL quan hệ, trong khi đó HQL được dùng để truy vấn các đối tượng.
4.1. Sử dụng HQL:
Các câu truy vấn của Hibernate thì có cấu trúc tương tự như SQL với mệnh đề SELECT, FORM và WHERE. HQL cũng hỗ trợ subselect nếu chúng được hỗ trợ bởi 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:
List results = session.find("from Event");
4.1.2. Giao tiếp Query:
Các thể hiện của giao tiếp Query được tạo bởi Session. Giao tiếp Query cho phép bạn điều khiển các đối tượng được trả về nhiều hơn như giới hạnh số đối tượng được trả về, thiết lập timeout cho câu truy vấn.
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>
Truy cập named queries như sau:
Query q = session.getNamedQuery("Event.byName");
…
List results = q.list();
4.2. Show SQL:
Để debug HQL, bạn cần xem SQL được phát sinh để đảm bảo câu truy vấn đang làm những gì mà bạn mong đợi. Thiết lập thuộc tính show_sql là true sẽ phát sinh ra SQL trên console.
Thiết lập thuộc tính này trong hibenate.cfg.xml:
<property name="show_sql">true</property>
4.3. Joins:
from Event e join e.attendees a where a.id=314 => rút trích các thể hiện của Event với id xác định của Attendee.
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.
4.4. Sử dụng hàm:
Hàm là các lệnh đặc biệt trả về giá trị đã được tính toán. Hibernate hỗ trợ 5 hàm sau: avg, min, max và sum.
* avg(expression) - tính giá trị trung bình của biểu thức.
* count(expression) - đếm số dòng được trả về bởi biểu thức.
* max(expression) - trả về giá trị lớn nhất trong biểu thức.
* min(expression) - trả về giá trị nhỏ nhất trong biểu thức.
* sum(expression) - trả về tổng các giá trị trong biểu thức.
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.
Criteria criteria = session.createCriteria(Event.class);
criteria.add(Restrictions.between("duration", new Integer(60), new Integer(90) );
criteria.add( Restrictions.like("name", "Presen%") );
criteria.addOrder( Order.asc("name") );
List results = criteria.list();
(Còn tiếp ....)
Nguồn : tham khảo javavietnam.org
Không có nhận xét nào:
Đăng nhận xét