Trong JPA thì đối tượng EntityManagerFactory sẽ là đối tượng quản lý các entity, quản lý kết nối đến database. Việc sử dụng Spring để quản lý đối tượng này sẽ giúp chúng ta rất nhiều trong việc phát triển các ứng dụng Java có sử dụng JPA. Trong bài viết này, mình sẽ hướng dẫn các bạn cách sử dụng JPA với Spring framework các bạn nhé!
Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:
Spring framework dependency:
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.3</version> </dependency> |
Để làm việc với JPA, chúng ta cũng cần thêm spring-orm dependency nữa:
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>6.0.3</version> </dependency> |
Ở đây, mình sẽ sử dụng JPA với implementation của Hibernate nên mình sẽ thêm Hibernate dependency như sau:
1 2 3 4 5 |
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.1.6.Final</version> </dependency> |
MySQL Connector:
1 2 3 4 5 |
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.31</version> </dependency> |
Để đơn giản, trong ví dụ này, mình chỉ định nghĩa một table chứa thông tin sinh viên với 2 cột như sau:
1 2 3 4 5 |
CREATE TABLE `student` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; |
Entity của table student có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.huongdanjava.springjpa.entity; import java.io.Serializable; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; @Table(name = "student") @Entity public class Student implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue private Long id; @Column private String 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; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } } |
Để làm việc với JPA, chúng ta cần có một tập tin cấu hình persistence.xml cho nó. Các bạn hãy tạo mới tập tin persistence.xml nằm trong thư mục /src/main/resources/META-INF các bạn nhé!
Nội dung của tập tin này như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="springPU" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.huongdanjava.springjpa.entity.Student</class> <exclude-unlisted-classes /> <properties> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="false" /> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.validation.mode" value="none" /> </properties> </persistence-unit> </persistence> |
Bây giờ sẽ là phần quan trọng nhất, khai báo đối tượng EntityManagerFactory trong Spring container.
Trong Spring, hiện tại chúng ta có hai class hỗ trợ cho việc khai báo đối tượng EntityManagerFactory đó là:
- LocalContainerEntityManagerFactoryBean
- LocalEntityManagerFactoryBean
Với class LocalEntityManagerFactoryBean thì tập tin cấu hình của JPA persistence.xml thường nằm trong thư mục META-INF/persistence.xml, tuy nhiên với class LocalContainerEntityManagerFactoryBean thì location của tập tin persistence.xml sẽ linh hoạt hơn, chúng ta có thể override lại location của nó và việc sử dụng LocalContainerEntityManagerFactoryBean sẽ giúp các bạn có thể khai báo JDBC Datasources linh hoạt hơn nữa.
Mình sẽ sử dụng LocalContainerEntityManagerFactoryBean trong ví dụ này với khai báo cho nó trong Spring container như sau:
1 2 3 4 5 6 7 |
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="persistenceUnitName" value="springPU" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> </bean> |
Như các bạn thấy, có 3 thuộc tính mà chúng ta cần phải khai báo cùng với class LocalContainerEntityManagerFactory đó là:
- dataSource: thuộc tính này dùng để khai báo DataSource cho EntityManagerFactory của chúng ta. DataSource ở đây chúng ta có thể hiểu nôm na là phần quản lý kết nối tới database. Chúng ta có thể khai báo nhiều loại DataSource khác nhau do nhiều tổ chức khác nhau implement interface javax.sql.DataSource.
- persistenceUnitName: đây là tên của Persistence Unit mà chúng ta đã khai báo trong tập tin cấu hình của JPA, persistence.xml.
- jpaVendorAdapter: thuộc tính này dùng để khai báo thư viện chúng ta sẽ sử dụng cho phần implementation của JPA. Trong ví dụ này, mình sử dụng Hibernate nên khai báo là HibernateJpaVendorAdapter. Nếu các bạn sử dụng EclipseLink làm implementation của JPA thì hãy khai báo thuộc tính này là org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter.
Phần dataSource trong ví dụ này mình sẽ sử dụng DriverManagerDataSource với các khai báo như chúng ta làm cho JDBC, như sau:
1 2 3 4 5 6 |
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/muleesb_jpa" /> <property name="username" value="root" /> <property name="password" value="123456" /> </bean> |
OK, vậy là chúng ta đã hoàn thành việc khai báo EntityManagerFactory trong Spring container. Giờ thì sử dụng nó thôi!
Ví dụ của mình như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.huongdanjava.springjpa.entity; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; public class Application { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); EntityManagerFactory emf = (EntityManagerFactory) ac.getBean("entityManagerFactory"); EntityManager em = emf.createEntityManager(); Student student = em.find(Student.class, Long.valueOf(1)); System.out.println(student.getName()); } } |
Hiện tại database của mình đang có dữ liệu như sau:
nên kết quả sẽ là:
độ
anh có fb hay gì ko ạ cho em xin em hỏi chút vấn đề ạ
Khanh Nguyen
Hỏi ở đây nè em https://www.facebook.com/groups/721409674679531/?ref=bookmarks
Hung Pham
Bạn cho mình hỏi là khi khai báo :
Nhưng khi dùng :
EntityManagerFactory emf = (EntityManagerFactory) ac.getBean(“entityManagerFactory”);
Mình xem thì ko thấy mối liên hệ nào giữa LocalContainerEntityManagerFactoryBean và EntityManagerFactory.
làm sao để spring hiểu được như vậy? Thanks!
Khanh Nguyen
Bạn xem như thế nào thế?
thuong_java
anh xem giúp e lỗi này là gì ạ
Error creating bean with name ‘studentDaoImpl’: Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’
Khanh Nguyen
File cấu hình Spring của bạn như thế nào nhỉ?