CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Mục lục

Trang chủBlogỨng dụng Spring ORM với J...
Java

Ứng dụng Spring ORM với JPA, Hibernate, Transaction

6 phút đọc22/09/2025
CyStack Author
Chris Pham

Technical Writer

0 lượt xem
Reading Time: 6 minutes

Ứng dụng Spring ORM

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.

Ứn dụng Spring ORM với JPA, Hibernate, Transaction

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.


	4.0.0

	hu.daniel.hari.learn.spring
	Tutorial-SpringORMwithTX
	0.0.1-SNAPSHOT
	jar

	
		
		UTF-8
		1.7

		
		4.0.0.RELEASE
		4.1.9.Final

	

	
		
		
			log4j
			log4j
			1.2.17
		

		
		
			org.springframework
			spring-context
			${spring.version}
		
		
			org.springframework
			spring-orm
			${spring.version}
		

		
		
			org.hibernate
			hibernate-entitymanager
			${hibernate.version}
		

		
		
			hsqldb
			hsqldb
			1.8.0.7
		

	

	
		
			
				org.apache.maven.plugins
				maven-compiler-plugin
				3.1
				
					${java.version}
					${java.version}
				
			
		
	


  • Chúng ta cần spring-contextspring-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@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 persistfindAll.

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, addAlllistAll.

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.



	
	
	
	
	

	
		
		
		
		
	
	
	
		
			
				
				
			
		
	

	
	
		
	
	
	


  1. Đầ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.
  2. Thêm datasource, hiện tại là database trong bộ nhớ HSQLDB.
  3. 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:
    1. Thuộc tính packagesToScan trỏ đến package chứa các model class của chúng ta.
    2. datasource đã được định nghĩa trước đó trong file cấu hình Spring.
    3. jpaVendorAdapter là Hibernate và được thiết lập một số thuộc tính cho Hibernate.
  4. 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.
  5. 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 Pham
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