Ứng dụng Spring ORM với JPA, Hibernate, Transaction
6 phút đọc22/09/2025
Chris Pham
Technical Writer
0 lượt xem
0 lượt xem
Reading Time: 6minutes
Trong bài viết này, chúng ta sẽ cùng tìm hiểu một ví dụ về Spring ORM sử dụng Hibernate và JPA để quản lý transaction. Ta sẽ đi qua một ví dụ rất đơn giản về ứng dụng Spring với các tính năng:
Dependency Injection (tiêm phụ thuộc) với @Autowired
JPA EntityManager (cung cấp bởi Hibernate)
Phương thức giao dịch dùng annotation (@Transactional)
Một project Spring ORM mẫu
Trong ví dụ này, ta sử dụng database trong bộ nhớ (in-memory). Vì vậy bạn không cần phải cài đặt bất kỳ database nào (nhưng bạn có thể thay đổi sang một database khác trong mục datasource của file spring.xml).
Đây là một ứng dụng Spring ORM chạy riêng lẻ để tối giản các dependency (phụ thuộc). Nhưng bạn luôn có thể dễ dàng chuyển đổi nó thành một dự án web hoàn chỉnh bằng cách cấu hình nó nếu bạn đã quen thuộc với Spring.
Trước hết, hãy cùng xem xét từng thành phần của dự án.
Các dependency Maven
Dưới đây là file pom.xml cuối cùng chứa các dependency cho Spring ORM. Trong ví dụ này, chúng ta sử dụng Spring 4 và Hibernate 4.
Chúng ta cần spring-context và spring-orm làm các dependency của Spring.
Ta sử dụng hibernate-entitymanager cho Hibernate với vai trò là một triển khai của JPA. Nó phụ thuộc vào hibernate-core, đó là lý do chúng ta không cần khai báo hibernate-core một cách tường minh trong file pom.xml. Nó sẽ được tải về dự án của chúng ta thông qua cơ chế bắc cầu dependency (transitive dependency) của Maven.
Chúng ta cũng cần dependency cho JDBC driver để truy cập database. Ở đây, ta sử dụng HSQLDB, vốn đã bao gồm cả JDBC driver và một database trong bộ nhớ có thể hoạt động ngay.
Model class
Chúng ta có thể sử dụng các annotation JPA tiêu chuẩn để map (ánh xạ) trong các model bean vì Hibernate cung cấp sẵn một triển khai của JPA.
package hu.daniel.hari.learn.spring.orm.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer id;
private String name;
public Product() {
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + "]";
}
}
Chúng ta sử dụng các annotation @Entity và @Id của JPA để định danh POJO của ta là một Entity và để xác định khóa chính cho nó.
Class DAO
Chúng ta tạo một class DAO rất đơn giản cung cấp các method persist và findAll.
package hu.daniel.hari.learn.spring.orm.dao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
@Component
public class ProductDao {
@PersistenceContext
private EntityManager em;
public void persist(Product product) {
em.persist(product);
}
public List findAll() {
return em.createQuery("SELECT p FROM Product p").getResultList();
}
}
@Component là một annotation của Spring, cho Spring container biết rằng chúng ta có thể sử dụng class này thông qua Spring IoC (Dependency Injection).
Chúng ta sử dụng annotation @PersistenceContext của JPA để yêu cầu dependency injection một EntityManager. Spring sẽ inject (chèn) một thực thể EntityManager phù hợp dựa theo cấu hình trong spring.xml.
Class service
Class service đơn giản của chúng ta có 2 method ghi và 1 method đọc:- add, addAll và listAll.
package hu.daniel.hari.learn.spring.orm.service;
import hu.daniel.hari.learn.spring.orm.dao.ProductDao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional
public void add(Product product) {
productDao.persist(product);
}
@Transactional
public void addAll(Collection products) {
for (Product product : products) {
productDao.persist(product);
}
}
@Transactional(readOnly = true)
public List listAll() {
return productDao.findAll();
}
}
Chúng ta sử dụng annotation @Autowired của Spring để inject ProductDao vào class service.
Vì ta muốn sử dụng quản lý transaction, các method được đánh dấu bằng annotation @Transactional của Spring. Method listAll chỉ đọc database, vì vậy chúng ta đặt annotation @Transactional ở chế độ chỉ đọc (read-only) để tối ưu hóa nó.
File cấu hình bean
Khi đã có đủ các class Java cho dự án ví dụ, tiếp theo ta sẽ xem qua file cấu hình Spring bean spring.xml.
Đầu tiên, chúng ta cho Spring biết rằng ta muốn sử dụng cơ chế quét classpath (classpath scanning) cho các thành phần Spring (Service, DAO) thay vì phải định nghĩa từng bean một trong file XML. Chúng ta cũng đã kích hoạt việc nhận diện annotation của Spring.
Thêm datasource, hiện tại là database trong bộ nhớ HSQLDB.
Chúng ta thiết lập một JPA EntityManagerFactory để ứng dụng sử dụng để lấy một EntityManager. Spring hỗ trợ 3 cách khác nhau để thực hiện việc này, và ở đây chúng ta đã sử dụng LocalContainerEntityManagerFactoryBean để có đầy đủ các tính năng của JPA. Chúng ta thiết lập các thuộc tính của nó như sau:
Thuộc tính packagesToScan trỏ đến package chứa các model class của chúng ta.
datasource đã được định nghĩa trước đó trong file cấu hình Spring.
jpaVendorAdapter là Hibernate và được thiết lập một số thuộc tính cho Hibernate.
Chúng ta tạo một thực thể PlatformTransactionManager của Spring dưới dạng JpaTransactionManager. Loại transaction manager (quản lý giao dịch) này phù hợp cho các ứng dụng sử dụng một EntityManagerFactory duy nhất của JPA để truy cập dữ liệu.
Chúng ta kích hoạt việc cấu hình hành vi transaction dựa trên annotation, và thiết lập transactionManager mà chúng ta vừa tạo.
Chương trình kiểm thử
Sau khi có một ví dụ hoàn chỉnh, giờ ta sẽ viết một chương trình để kiểm thử nó.
public class SpringOrmMain {
public static void main(String[] args) {
//Create Spring application context
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//Get service from context. (service's dependency (ProductDAO) is autowired in ProductService)
ProductService productService = ctx.getBean(ProductService.class);
//Do some data operation
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//Test transaction rollback (duplicated key)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//Test element list after rollback
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
Bạn có thể thấy chúng ta có thể khởi động Spring container từ một method main dễ dàng như thế nào. Chúng ta đang lấy entry point (điểm đầu vào) đầu tiên được inject dependency, đó là thực thể của class service.
Tham chiếu của class ProductDao được inject vào class Client sau khi spring context được khởi tạo. Sau khi có được thực thể productService, chúng ta có thể kiểm thử các method của nó. Mọi lời gọi method sẽ đều có tính chất transactional (giao dịch) nhờ vào cơ chế proxy của Spring. Trong ví dụ này, chúng ta cũng kiểm thử cả chức năng rollback (đưa hệ thống hoặc dữ liệu về lại trạng thái ổn định trước đó).
Nếu bạn chạy chương trình kiểm thử trên, bạn sẽ nhận được log như dưới đây.
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Lưu ý rằng transaction thứ hai đã được rollback, đó là lý do tại sao danh sách sản phẩm không thay đổi. Nếu bạn sử dụng file log4j.properties từ code đính kèm, bạn có thể thấy những gì đang diễn ra ở bên trong ứng dụng.
Bạn có thể tải về dự án ví dụ Spring ORM hoàn chỉnh từ liên kết này và thử nghiệm thêm để tìm hiểu sâu hơn về các ứng dụng dạng này.
Về tác giả
Chris PhamTechnical Writer
I have over 5 years of experience writing technical documentation for tech products, making them accessible and user-friendly. My focus is always on providing clear and precise information.
@#@
Tôi đã có hơn 5 năm kinh nghiệm viết tài liệu kỹ thuật cho các sản phẩm công nghệ, giúp người dùng dễ dàng tiếp cận và sử dụng. Tôi luôn tập trung vào việc cung cấp thông tin chính xác và dễ hiểu.
Cập nhật thông tin mới nhấtNhận các thông tin mới nhất về mối đe dọa, báo cáo an ninh mạng từ CyStack về hòm thư điện tử của bạn
Thảo luận (0)
Đăng nhập để thảo luận
Bài viết liên quan
{"success":true,"head":"<title>Ứng dụng Spring ORM với JPA, Hibernate, Transaction - CyStack Tutorial</title>\n<meta name=\"description\" content=\"Hãy xem bài hướng dẫn này để tạo một ứng dụng Spring ORM hoàn chỉnh với Hibernate và HSQLDB, giúp bạn thực hành mà không cần cài đặt database phức tạp.\"/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-video-preview:-1, max-image-preview:large\"/>\n<link rel=\"canonical\" href=\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/\" />\n<meta property=\"og:locale\" content=\"en_US\" />\n<meta property=\"og:type\" content=\"article\" />\n<meta property=\"og:title\" content=\"Ứng dụng Spring ORM với JPA, Hibernate, Transaction - CyStack Tutorial\" />\n<meta property=\"og:description\" content=\"Hãy xem bài hướng dẫn này để tạo một ứng dụng Spring ORM hoàn chỉnh với Hibernate và HSQLDB, giúp bạn thực hành mà không cần cài đặt database phức tạp.\" />\n<meta property=\"og:url\" content=\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/\" />\n<meta property=\"og:site_name\" content=\"CyStack Tutorial\" />\n<meta property=\"article:tag\" content=\"vi\" />\n<meta property=\"article:section\" content=\"Java\" />\n<meta property=\"og:image\" content=\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\" />\n<meta property=\"og:image:secure_url\" content=\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\" />\n<meta property=\"og:image:width\" content=\"1200\" />\n<meta property=\"og:image:height\" content=\"630\" />\n<meta property=\"og:image:alt\" content=\"Ứng dụng Spring ORM\" />\n<meta property=\"og:image:type\" content=\"image/jpeg\" />\n<meta property=\"article:published_time\" content=\"2025-09-22T16:14:04+07:00\" />\n<meta name=\"twitter:card\" content=\"summary_large_image\" />\n<meta name=\"twitter:title\" content=\"Ứng dụng Spring ORM với JPA, Hibernate, Transaction - CyStack Tutorial\" />\n<meta name=\"twitter:description\" content=\"Hãy xem bài hướng dẫn này để tạo một ứng dụng Spring ORM hoàn chỉnh với Hibernate và HSQLDB, giúp bạn thực hành mà không cần cài đặt database phức tạp.\" />\n<meta name=\"twitter:image\" content=\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\" />\n<meta name=\"twitter:label1\" content=\"Written by\" />\n<meta name=\"twitter:data1\" content=\"Chris Pham\" />\n<meta name=\"twitter:label2\" content=\"Time to read\" />\n<meta name=\"twitter:data2\" content=\"10 minutes\" />\n<script type=\"application/ld+json\" class=\"rank-math-schema\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https://blog.cystack.org/tutorial/#person\",\"name\":\"CyStack Tutorial\"},{\"@type\":\"WebSite\",\"@id\":\"https://blog.cystack.org/tutorial/#website\",\"url\":\"https://blog.cystack.org/tutorial\",\"name\":\"CyStack Tutorial\",\"publisher\":{\"@id\":\"https://blog.cystack.org/tutorial/#person\"},\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\",\"url\":\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\",\"width\":\"1200\",\"height\":\"630\",\"caption\":\"\\u1ee8ng d\\u1ee5ng Spring ORM\",\"inLanguage\":\"en-US\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":\"1\",\"item\":{\"@id\":\"https://blog.cystack.org/tutorial\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":\"2\",\"item\":{\"@id\":\"https://blog.cystack.org/tutorial/category/java/\",\"name\":\"Java\"}},{\"@type\":\"ListItem\",\"position\":\"3\",\"item\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/\",\"name\":\"\\u1ee8ng d\\u1ee5ng Spring ORM v\\u1edbi JPA, Hibernate, Transaction\"}}]},{\"@type\":\"WebPage\",\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#webpage\",\"url\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/\",\"name\":\"\\u1ee8ng d\\u1ee5ng Spring ORM v\\u1edbi JPA, Hibernate, Transaction - CyStack Tutorial\",\"datePublished\":\"2025-09-22T16:14:04+07:00\",\"dateModified\":\"2025-09-22T16:14:04+07:00\",\"isPartOf\":{\"@id\":\"https://blog.cystack.org/tutorial/#website\"},\"primaryImageOfPage\":{\"@id\":\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\"},\"inLanguage\":\"en-US\",\"breadcrumb\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#breadcrumb\"}},{\"@type\":\"Person\",\"@id\":\"https://blog.cystack.org/tutorial/author/codeweaver/\",\"name\":\"Chris Pham\",\"url\":\"https://blog.cystack.org/tutorial/author/codeweaver/\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https://secure.gravatar.com/avatar/7a3584c941fa360ac061b2a8f15684ced7b92daa1f09481be135a684d989e9b9?s=96&d=mm&r=g\",\"url\":\"https://secure.gravatar.com/avatar/7a3584c941fa360ac061b2a8f15684ced7b92daa1f09481be135a684d989e9b9?s=96&d=mm&r=g\",\"caption\":\"Chris Pham\",\"inLanguage\":\"en-US\"}},{\"@type\":\"BlogPosting\",\"headline\":\"\\u1ee8ng d\\u1ee5ng Spring ORM v\\u1edbi JPA, Hibernate, Transaction - CyStack Tutorial\",\"keywords\":\"\\u1ee9ng d\\u1ee5ng Spring ORM\",\"datePublished\":\"2025-09-22T16:14:04+07:00\",\"dateModified\":\"2025-09-22T16:14:04+07:00\",\"articleSection\":\"Java\",\"author\":{\"@id\":\"https://blog.cystack.org/tutorial/author/codeweaver/\",\"name\":\"Chris Pham\"},\"publisher\":{\"@id\":\"https://blog.cystack.org/tutorial/#person\"},\"description\":\"H\\u00e3y xem b\\u00e0i h\\u01b0\\u1edbng d\\u1eabn n\\u00e0y \\u0111\\u1ec3 t\\u1ea1o m\\u1ed9t \\u1ee9ng d\\u1ee5ng Spring ORM ho\\u00e0n ch\\u1ec9nh v\\u1edbi Hibernate v\\u00e0 HSQLDB, gi\\u00fap b\\u1ea1n th\\u1ef1c h\\u00e0nh m\\u00e0 kh\\u00f4ng c\\u1ea7n c\\u00e0i \\u0111\\u1eb7t database ph\\u1ee9c t\\u1ea1p.\",\"name\":\"\\u1ee8ng d\\u1ee5ng Spring ORM v\\u1edbi JPA, Hibernate, Transaction - CyStack Tutorial\",\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#richSnippet\",\"isPartOf\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#webpage\"},\"image\":{\"@id\":\"https://s2.cystack.net/tutorial/22161258/ung-dung-spring-orm.jpg\"},\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/09/22/ung-dung-spring-orm/#webpage\"}}]}</script>\n"}