Hướng dẫn tích hợp Spring MVC, Hibernate, và MySQL trong ứng dụng CRUD
9 phút đọc22/05/2025
Chris Pham
Technical Writer
0 lượt xem
0 lượt xem
Reading Time: 9minutes
Trong bài hướng dẫn trước, chúng ta đã tìm hiểu cách sử dụng Spring và Hibernate. Hôm nay, chúng ta sẽ tiếp tục tích hợp Spring MVC, Hibernate, và MySQL thông qua một ví dụ CRUD trong ứng dụng web. Cấu trúc project cuối cùng của chúng ta có dạng như dưới đây.
Trong bài viết này chúng ta sẽ đi qua từng thành phần một. Lưu ý rằng bài này sử dụng phiên bản Spring 4.0.3.Release và Hibernate 4.3.5.Final. Nó cũng tương thích với Spring 4 và Hibernate 3, tuy nhiên bạn cần thực hiện một vài thay đổi nhỏ trong file cấu hình Spring bean như đã được đề cập ở tutorial trước.
Để chạy thử ví dụ này, trước hết hãy tải code của ví dụ về từ repo GitHub này.
Các dependency Maven
Hãy cùng xem xét tất cả các dependency Maven cần cho việc dùng Hibernate với Spring MVC.
Một số dependency ở trên được STS (Spring Tool Suite) tự động thêm vào khi tạo project Spring MVC. Các dependency quan trọng bao gồm spring-context, spring-webmvc, spring-tx, hibernate-core, hibernate-entitymanager và spring-orm.
Ở đây ta đang sử dụng Apache Commons DBCP cho connection pooling. Nhưng trong thực tế, thường thì container sẽ đảm nhiệm connection pooling và chúng ta chỉ cần cung cấp thông tin tham chiếu JNDI để sử dụng.
Lưu ý: Một số bạn đã gặp vấn đề về kết nối database. Lưu ý rằng trong file pom.xml của chúng tôi không có database driver trong đó. Tuy vậy, nó vẫn hoạt động được vì đã có driver MySQL trong thư mục lib của Tomcat và một số cấu hình DataSource connection sử dụng nó.
Nếu bạn gặp vấn đề với kết nối database, hãy thử đặt database driver vào thư mục lib của container hoặc khai báo nó trong dependency của file pom.xml.
Deployment Descriptor
Để tích hợp Spring vào một ứng dụng web, chúng ta cần cấu hình DispatcherServlet của Spring làm front controller. File web.xml của chúng ta trông như sau.
Phần lớn nội dung trên là boilerplate code. Phần quan trọng nhất là vị trí của file Spring context, nơi chúng ta sẽ cấu hình các Spring bean và service. Bạn có thể thay đổi chúng tùy theo yêu cầu của project.
Hibernate Entity Bean
Chúng ta đang sử dụng JPA annotation trong class entity bean, tuy nhiên, chúng ta cũng có thể dùng một Java bean đơn giản và định nghĩa thông tin mapping trong file XML. Trong trường hợp đó, chúng ta cần cung cấp đường dẫn đến file mapping khi cấu hình Hibernate SessionFactory trong phần cấu hình Spring bean.
package com.journaldev.spring.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Entity bean with JPA annotations
* Hibernate provides JPA implementation
* @author pankaj
*
*/
@Entity
@Table(name="PERSON")
public class Person {
@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private String country;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString(){
return "id="+id+", name="+name+", country="+country;
}
}
Entity bean của chúng ta map với bảng PERSON trong database MySQL. Lưu ý rằng ta không dùng annotation @Column cho các trường “name” và “country” vì tên trường và tên cột là giống nhau.
Script SQL dưới đây diễn tả chi tiết hơn về bảng đó:
Chúng ta sẽ tạo interface PersonDAO để khai báo các phương thức sẽ sử dụng trong project. Tiếp theo, chúng ta sẽ cung cấp phần triển khai cụ thể bằng Hibernate cho interface này.
package com.journaldev.spring.dao;
import java.util.List;
import com.journaldev.spring.model.Person;
public interface PersonDAO {
public void addPerson(Person p);
public void updatePerson(Person p);
public List listPersons();
public Person getPersonById(int id);
public void removePerson(int id);
}
Phần triển khai DAO bằng Hibernate trông như sau.
package com.journaldev.spring.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import com.journaldev.spring.model.Person;
@Repository
public class PersonDAOImpl implements PersonDAO {
private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
@Override
public void addPerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(p);
logger.info("Person saved successfully, Person Details="+p);
}
@Override
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
logger.info("Person updated successfully, Person Details="+p);
}
@SuppressWarnings("unchecked")
@Override
public List listPersons() {
Session session = this.sessionFactory.getCurrentSession();
List personsList = session.createQuery("from Person").list();
for(Person p : personsList){
logger.info("Person List::"+p);
}
return personsList;
}
@Override
public Person getPersonById(int id) {
Session session = this.sessionFactory.getCurrentSession();
Person p = (Person) session.load(Person.class, new Integer(id));
logger.info("Person loaded successfully, Person details="+p);
return p;
}
@Override
public void removePerson(int id) {
Session session = this.sessionFactory.getCurrentSession();
Person p = (Person) session.load(Person.class, new Integer(id));
if(null != p){
session.delete(p);
}
logger.info("Person deleted successfully, person details="+p);
}
}
Lưu ý rằng ta không sử dụng Hibernate Transaction, vì việc này sẽ do Spring đảm nhiệm.
Các class Service của Spring
Đây là các class service sử dụng các class Hibernate DAO để làm việc với đối tượng Person.
package com.journaldev.spring.service;
import java.util.List;
import com.journaldev.spring.model.Person;
public interface PersonService {
public void addPerson(Person p);
public void updatePerson(Person p);
public List listPersons();
public Person getPersonById(int id);
public void removePerson(int id);
}
package com.journaldev.spring.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.dao.PersonDAO;
import com.journaldev.spring.model.Person;
@Service
public class PersonServiceImpl implements PersonService {
private PersonDAO personDAO;
public void setPersonDAO(PersonDAO personDAO) {
this.personDAO = personDAO;
}
@Override
@Transactional
public void addPerson(Person p) {
this.personDAO.addPerson(p);
}
@Override
@Transactional
public void updatePerson(Person p) {
this.personDAO.updatePerson(p);
}
@Override
@Transactional
public List listPersons() {
return this.personDAO.listPersons();
}
@Override
@Transactional
public Person getPersonById(int id) {
return this.personDAO.getPersonById(id);
}
@Override
@Transactional
public void removePerson(int id) {
this.personDAO.removePerson(id);
}
}
Lưu ý rằng cơ chế quản lý transaction khai báo (declarative transaction) của Spring được áp dụng thông qua annotation @Transactional.
Class Controller của Spring
Ta đã xong với class DAO và Service, giờ là lúc viết class controller. Class này sẽ xử lý các request từ client, sử dụng các class service để thực hiện các thao tác với database, và sau đó trả về các trang view.
package com.journaldev.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.service.PersonService;
@Controller
public class PersonController {
private PersonService personService;
@Autowired(required=true)
@Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
@RequestMapping(value = "/persons", method = RequestMethod.GET)
public String listPersons(Model model) {
model.addAttribute("person", new Person());
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
//For add and update person both
@RequestMapping(value= "/person/add", method = RequestMethod.POST)
public String addPerson(@ModelAttribute("person") Person p){
if(p.getId() == 0){
//new person, add it
this.personService.addPerson(p);
}else{
//existing person, call update
this.personService.updatePerson(p);
}
return "redirect:/persons";
}
@RequestMapping("/remove/{id}")
public String removePerson(@PathVariable("id") int id){
this.personService.removePerson(id);
return "redirect:/persons";
}
@RequestMapping("/edit/{id}")
public String editPerson(@PathVariable("id") int id, Model model){
model.addAttribute("person", this.personService.getPersonById(id));
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
}
Lưu ý rằng ta sử dụng annotation @Controller, để Spring xem đây là một class Controller xử lý các request từ client. Ta cũng đang dùng annotation @Autowired và @Qualifier để inject PersonService. Chúng ta cũng có thể thực hiện việc này trong file XML của Spring context.
Cấu hình Spring Bean
Các service của chúng ta đã sẵn sàng, giờ chỉ cần kết nối chúng lại thông qua cấu hình Spring bean. File root-context.xml của chúng ta chưa có gì, vì vậy chúng ta sẽ chỉ xem xét file servlet-context.xml.
dataSource bean được định nghĩa cho class org.apache.commons.dbcp.BasicDataSource để thực hiện connection pooling cơ bản.
Bean org.springframework.orm.hibernate4.LocalSessionFactoryBean được sử dụng cho SessionFactory của Hibernate 4. Đối với Hibernate 3, bạn sẽ tìm thấy các class tương tự là org.springframework.orm.hibernate3.LocalSessionFactoryBean và org.springframework.orm.hibernate3.AnnotationSessionFactoryBean.
Một điểm quan trọng là khi chúng ta dựa vào Spring framework để quản lý Hibernate Session, chúng ta không nên định nghĩa thuộc tính hibernate.current_session_context_class, nếu không bạn sẽ gặp nhiều vấn đề liên quan đến session transaction.
Các bean personDAO và personService khá dễ hiểu. Cần phải định nghĩa bean transactionManager cho org.springframework.orm.hibernate4.HibernateTransactionManager để Spring ORM hỗ trợ quản lý transaction cho Hibernate session.
Đối với Hibernate 3, bạn sẽ tìm thấy class tương tự là org.springframework.orm.hibernate3.HibernateTransactionManager. Spring sử dụng AOP để quản lý transaction. Bạn có thể liên hệ điều này với annotation @Transactional.
Trang View
Phần cuối cùng của ứng dụng là trang view. Hãy chú ý các attribute được thêm vào Model trong các phương thức xử lý (handler methods) của Controller, chúng ta sẽ sử dụng chúng để tạo trang view. Chúng ta cũng sẽ sử dụng các thẻ JSTL, thẻ Spring core và thẻ Spring form.
Hãy build và deploy project vào bất kỳ servlet container nào bạn thích, ví dụ như Tomcat. Dưới đây là hình ảnh các trang view của ứng dụng.
Ta cũng sẽ tìm thấy các log tương tự trong file log của server.
Hibernate: insert into PERSON (country, name) values (?, ?)
INFO : com.journaldev.spring.dao.PersonDAOImpl - Person saved successfully, Person Details=id=15, name=Pankaj, country=USA
Hibernate: select person0_.id as id1_0_, person0_.country as country2_0_, person0_.name as name3_0_ from PERSON person0_
INFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=10, name=Raman, country=UK2
INFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=11, name=Lisa, country=France
INFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=15, name=Pankaj, country=USA
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>Hướng dẫn tích hợp Spring MVC, Hibernate, và MySQL trong ứng dụng CRUD - CyStack Tutorial</title>\n<meta name=\"description\" content=\"Đọc bài viết này để tìm hiểu quy trình từng bước tích hợp Spring MVC, Hibernate, MySQL để phát triển ứng dụng web có đầy đủ các thao tác CRUD cơ bản.\"/>\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/05/22/tich-hop-spring-mvc-hibernate-va-mysql/\" />\n<meta property=\"og:locale\" content=\"en_US\" />\n<meta property=\"og:type\" content=\"article\" />\n<meta property=\"og:title\" content=\"Hướng dẫn tích hợp Spring MVC, Hibernate, và MySQL trong ứng dụng CRUD - CyStack Tutorial\" />\n<meta property=\"og:description\" content=\"Đọc bài viết này để tìm hiểu quy trình từng bước tích hợp Spring MVC, Hibernate, MySQL để phát triển ứng dụng web có đầy đủ các thao tác CRUD cơ bản.\" />\n<meta property=\"og:url\" content=\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/\" />\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:updated_time\" content=\"2025-06-04T18:11:32+07:00\" />\n<meta property=\"og:image\" content=\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL-1024x538.png\" />\n<meta property=\"og:image:secure_url\" content=\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL-1024x538.png\" />\n<meta property=\"og:image:width\" content=\"1024\" />\n<meta property=\"og:image:height\" content=\"538\" />\n<meta property=\"og:image:alt\" content=\"Tích hợp Spring MVC, Hibernate, và MySQL trong ứng dụng CRUD\" />\n<meta property=\"og:image:type\" content=\"image/png\" />\n<meta property=\"article:published_time\" content=\"2025-05-22T17:31:12+07:00\" />\n<meta property=\"article:modified_time\" content=\"2025-06-04T18:11:32+07:00\" />\n<meta name=\"twitter:card\" content=\"summary_large_image\" />\n<meta name=\"twitter:title\" content=\"Hướng dẫn tích hợp Spring MVC, Hibernate, và MySQL trong ứng dụng CRUD - CyStack Tutorial\" />\n<meta name=\"twitter:description\" content=\"Đọc bài viết này để tìm hiểu quy trình từng bước tích hợp Spring MVC, Hibernate, MySQL để phát triển ứng dụng web có đầy đủ các thao tác CRUD cơ bản.\" />\n<meta name=\"twitter:image\" content=\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL-1024x538.png\" />\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=\"20 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/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL.png\",\"url\":\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL.png\",\"width\":\"2400\",\"height\":\"1260\",\"caption\":\"T\\u00edch h\\u1ee3p Spring MVC, Hibernate, v\\u00e0 MySQL trong \\u1ee9ng d\\u1ee5ng CRUD\",\"inLanguage\":\"en-US\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#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/05/22/tich-hop-spring-mvc-hibernate-va-mysql/\",\"name\":\"H\\u01b0\\u1edbng d\\u1eabn t\\u00edch h\\u1ee3p Spring MVC, Hibernate, v\\u00e0 MySQL trong \\u1ee9ng d\\u1ee5ng CRUD\"}}]},{\"@type\":\"WebPage\",\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#webpage\",\"url\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/\",\"name\":\"H\\u01b0\\u1edbng d\\u1eabn t\\u00edch h\\u1ee3p Spring MVC, Hibernate, v\\u00e0 MySQL trong \\u1ee9ng d\\u1ee5ng CRUD - CyStack Tutorial\",\"datePublished\":\"2025-05-22T17:31:12+07:00\",\"dateModified\":\"2025-06-04T18:11:32+07:00\",\"isPartOf\":{\"@id\":\"https://blog.cystack.org/tutorial/#website\"},\"primaryImageOfPage\":{\"@id\":\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL.png\"},\"inLanguage\":\"en-US\",\"breadcrumb\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#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\":\"H\\u01b0\\u1edbng d\\u1eabn t\\u00edch h\\u1ee3p Spring MVC, Hibernate, v\\u00e0 MySQL trong \\u1ee9ng d\\u1ee5ng CRUD - CyStack Tutorial\",\"keywords\":\"t\\u00edch h\\u1ee3p Spring MVC,Hibernate,v\\u00e0 MySQL\",\"datePublished\":\"2025-05-22T17:31:12+07:00\",\"dateModified\":\"2025-06-04T18:11:32+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\":\"\\u0110\\u1ecdc b\\u00e0i vi\\u1ebft n\\u00e0y \\u0111\\u1ec3 t\\u00ecm hi\\u1ec3u quy tr\\u00ecnh t\\u1eebng b\\u01b0\\u1edbc t\\u00edch h\\u1ee3p Spring MVC, Hibernate, MySQL \\u0111\\u1ec3 ph\\u00e1t tri\\u1ec3n \\u1ee9ng d\\u1ee5ng web c\\u00f3 \\u0111\\u1ea7y \\u0111\\u1ee7 c\\u00e1c thao t\\u00e1c CRUD c\\u01a1 b\\u1ea3n.\",\"name\":\"H\\u01b0\\u1edbng d\\u1eabn t\\u00edch h\\u1ee3p Spring MVC, Hibernate, v\\u00e0 MySQL trong \\u1ee9ng d\\u1ee5ng CRUD - CyStack Tutorial\",\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#richSnippet\",\"isPartOf\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#webpage\"},\"image\":{\"@id\":\"https://s2.cystack.net/tutorial/22173055/Tich-hop-Spring-MVC-Hibernate-va-MySQL.png\"},\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https://blog.cystack.org/tutorial/2025/05/22/tich-hop-spring-mvc-hibernate-va-mysql/#webpage\"}}]}</script>\n"}