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
/src
├── controllers/
│ ├── LoginServlet.java
│ ├── LogoutServlet.java
│ ├── ProductServlet.java
├── models/
│ ├── User.java
│ ├── Product.java
├── repositories/ // Replace DALs (DAO)
│ ├── UserRepository.java
│ ├── ProductRepository.java
├── Utils/
│ ├── JPAUtil.java // That is EntityManagerFactory
// Replace DBContext.java
├── filters/
│ ├── AuthFilter.java (lọc quyền truy cập)
│
/webapp
├── META-INF/
│ ├── persistence.xml // JPA Configuration
├── WEB-INF/
│ ├── web.xml
│ ├── tags/
│ ├── layout.tag
├── views/
│ ├── login.jsp
│ ├── home.jsp
│ ├── product-management/
│ │ ├── addProduct.jsp
│ │ ├── updateProduct.jsp
│ │ ├── listProduct.jsp
│ │ ├── deleteProduct.jsp
Add dependencies into porm.xml in projects:
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- JPA API -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.3.0.Final</version>
</dependency>
Make sure you have
Build with dependenciesbefore running the project
persistence.xml is the main configuration file used by JPA (Jakarta Persistence API) to define how your Java application connects to a database and manages entities.
It is typically placed inside:
1
src/main/resources/META-INF/persistence.xml
This file tells the JPA provider (such as Hibernate, EclipseLink, etc.):
Inside persistence.xml, you define one or more persistence units — each representing a separate database configuration.
Each persistence unit is identified by a name:
1
2
3
<persistence-unit name="JSPShop">
...
</persistence-unit>
Note: name of persistence-unit. That is a name which select in DBContext. We need exact name.
When your code calls:
1
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JSPShop");
JPA looks up the configuration with the name JSPShop from persistence.xml and uses it to connect to the database.
Here’s a typical configuration using Hibernate with SQL Server:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" version="3.0">
<persistence-unit name="JSPShop">
<!-- Register entity classes -->
<class>Models.User</class>
<class>Models.Product</class>
<!-- Database connection properties -->
<properties>
<property name="jakarta.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="jakarta.persistence.jdbc.url" value="<CONNECTIONSTRING>"/>
<property name="jakarta.persistence.jdbc.user" value="<USER>"/>
<property name="jakarta.persistence.jdbc.password" value="<PASSWORDS>"/>
<!-- Hibernate properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
You need to fill all SQL Server infomation same as DBContext:
<CONNECTIONSTRING>: Connection String<USER> and <PASSWORDS>: User login into SQL Server.| Tag / Property | Description |
|---|---|
<persistence-unit name="..."> |
Defines a configuration group for JPA. Each unit has its own DB connection. |
<class> |
Lists all entity classes that should be managed by JPA. |
jakarta.persistence.jdbc.driver |
The JDBC driver used to connect to the database. |
jakarta.persistence.jdbc.url |
The database connection URL. |
jakarta.persistence.jdbc.user / password |
Credentials for the DB connection. |
hibernate.hbm2ddl.auto |
Defines schema generation strategy: create, update, validate, none. |
hibernate.show_sql |
Prints SQL statements in the console for debugging. |
hibernate.format_sql |
Formats SQL output for better readability. |
Common hibernate.hbm2ddl.auto Values:
| Value | Behavior |
|---|---|
create |
Drops and recreates the database schema on every startup. |
create-drop |
Creates schema at startup and drops it when the app stops. |
update |
Updates schema automatically to match entities (most common). |
validate |
Checks that schema matches entities; throws error if not. |
none |
Does nothing (manual schema management). |
In JPA (Jakarta Persistence API), an Entity is a lightweight, persistent domain object that represents a table in a relational database. Each instance of an entity corresponds to a single row (record) in that table.
An Entity is a POJO (Plain Old Java Object) class that is managed by the JPA provider and mapped to a database table through annotations or XML mapping. It defines the structure of the data, including fields (columns), relationships, and metadata that describe how the object maps to the database.
Keynotes:
Main materials:
classDiagram
class Persistence {
+createEntityManagerFactory()
}
class EntityManagerFactory {
+createEntityManager()
+close()
}
class EntityManager {
+persist(entity)
+merge(entity)
+remove(entity)
+find(entityClass, id)
+createQuery(query)
+getTransaction()
+close()
}
class EntityTransaction {
+begin()
+commit()
+rollback()
}
class Query {
+getResultList()
+getSingleResult()
+setParameter()
}
class Entity {
+id
+fields
}
Persistence --> EntityManagerFactory : creates
EntityManagerFactory --> EntityManager : creates
EntityManager --> EntityTransaction : manages
EntityManager --> Query : creates
EntityManager --> Entity : manages
| Component | Class / Annotation | Purpose | Example / Notes |
|---|---|---|---|
| Entity | @Entity |
Represents a database table. Managed by Hibernate / Jakarta Persistence. | @Entity class Product { ... } |
| EntityManagerFactory | jakarta.persistence.EntityManagerFactory |
Creates and manages EntityManager instances. Heavy resource; usually created once per application. |
EntityManagerFactory emf = Persistence.createEntityManagerFactory("unitName"); |
| EntityManager | jakarta.persistence.EntityManager |
Manages entity instances; performs CRUD, queries, and transactions. | EntityManager em = emf.createEntityManager(); |
| EntityTransaction | jakarta.persistence.EntityTransaction |
Manages transactions for write operations (persist, merge, remove). | EntityTransaction tx = em.getTransaction(); tx.begin(); ... tx.commit(); |
| Persistence | jakarta.persistence.Persistence |
Utility class to create EntityManagerFactory from persistence.xml. |
Persistence.createEntityManagerFactory("unitName"); |
| Query / TypedQuery | jakarta.persistence.Query, jakarta.persistence.TypedQuery |
Create and execute JPQL/SQL queries. | Query q = em.createQuery("SELECT p FROM Product p"); List<Product> list = q.getResultList(); |
How to update code-behide:
EntityManagerFactory: Using JPAUtil.java instead of DBConect.javaEntity for Models by anonymous parammeter in private variablesRepositories pattern to contain data instead of DALsRepositories for Servlets.| Responsibility | Description |
|---|---|
| Create EntityManager | Provides createEntityManager() method to create a new EntityManager (lightweight, short-lived). |
| Manage persistence unit | Reads configuration from persistence.xml, including DB connection, JPA provider, and mapping classes. |
| Resource management | Handles connection pools, caching, and other resources at the persistence unit level. |
| Thread-safe | Can be safely shared across multiple threads, unlike EntityManager which is not thread-safe. |
The JPA-based equivalent, which replaces DBContext.java.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Utils;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class JPAUtil {
private static final EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JSPShop");
public static EntityManagerFactory getEntityManagerFactory() {
return emf;
}
public static void close() {
emf.close();
}
}
An Entity is a Java class annotated with @Entity that represents a table in the database. Hibernate or JPA manages its persistence.
Maps class fields to table columns, encapsulates business data, and interacts with EntityManager for CRUD and query operations.
| Feature | Annotation / Mechanism | Description | Example |
|---|---|---|---|
| Primary Key | @Id, @GeneratedValue |
Unique identifier of the entity. Can auto-generate values. | @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; |
| Columns | @Column |
Maps Java fields to DB columns. Supports length, nullability, uniqueness. | @Column(name="product_name", nullable=false, length=100) private String name; |
| Relationships | @OneToOne, @OneToMany, @ManyToOne, @ManyToMany |
Links entities together; supports cascading and fetching strategies. | @OneToMany(mappedBy="product") private List<Order> orders; |
| Transient Fields | @Transient |
Field not persisted in DB. | @Transient private int tempCalculation; |
| Embedded Objects | @Embedded, @Embeddable |
Reuse complex types or composite keys within the entity. | @Embedded private Address address; |
| Lifecycle Callbacks | @PrePersist, @PostLoad, etc. |
Execute custom logic at certain points of the entity lifecycle. | @PrePersist void setCreatedAt() { this.createdAt = LocalDateTime.now(); } |
| Optimistic Locking | @Version |
Tracks entity version for concurrent updates. | @Version private int version; |
| Named Queries | @NamedQuery, @NamedQueries |
Predefined JPQL queries for reuse. | @NamedQuery(name="Product.findAll", query="SELECT p FROM Product p") |
Entity Validation:
| Feature | Annotation / Mechanism | Description | Example |
|---|---|---|---|
| Not Null / Required | @NotNull |
Field must not be null | @NotNull private String name; |
| Not Empty / Not Blank | @NotEmpty, @NotBlank |
String or collection must not be empty | @NotBlank private String description; |
| Size Constraints | @Size(min=, max=) |
Restrict length of strings or size of collections | @Size(max=100) private String title; |
| Number Constraints | @Min, @Max, @Positive, @Negative |
Restrict numeric values | @Min(0) @Max(1000) private int quantity; |
| Pattern / Regex | @Pattern(regexp="...") |
Field must match a regex pattern | @Pattern(regexp="\\d{10}") private String phoneNumber; |
| Email / Format Validation | @Email |
Validate email addresses | @Email private String email; |
| Custom Validation | @Constraint(validatedBy=...) |
Implement custom validation logic | Custom Validator class for complex rules |
| Cascade Validation | @Valid |
Validates nested / embedded objects | @Valid @Embedded private Address address; |
Update User Model (User.java)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package Models;
import jakarta.persistence.*;
@Entity
@Table(name = "Users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "UserID")
private int id;
@Column(name = "Username", nullable = false, length = 50, unique = true)
private String name;
@Column(name = "Password", nullable = false, length = 255)
private String password;
@Column(name = "Role", nullable = false, length = 20)
private String role;
public User() {
this.id = -1;
this.name = "";
this.password = "";
this.role = "";
}
public User(int id, String name, String password, String role) {
this.id = id;
this.name = name;
this.password = password;
this.role = role;
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public static boolean isEmpty(User user) {
return user == null || (user.getName() == null || user.getName().isEmpty());
}
}
Update Product Models (Product.java):
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package Models;
import jakarta.persistence.*;
@Entity
@Table(name = "Products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "name", nullable = false, length = 100)
private String name;
@Column(name = "description", columnDefinition = "TEXT")
private String description;
@Column(name = "price", nullable = false, precision = 10, scale = 2)
private double price;
@Column(name = "quantity", nullable = false)
private int quantity;
@Column(name = "image", nullable = false, length = 100)
private String image;
public Product() {
this.id = 0;
this.name = "";
this.price = 0;
this.description = "";
this.quantity = 0;
this.image = "";
}
public Product(String name, double price, String description, int quantity, String image) {
this.name = name;
this.price = price;
this.description = description;
this.quantity = quantity;
this.image = image;
}
public Product(int id, String name, double price, String description, int quantity, String image) {
this.id = id;
this.name = name;
this.price = price;
this.description = description;
this.quantity = quantity;
this.image = image;
}
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
}
We can create a generic repository to handle any entity type:
| Component | Definition / Role |
|---|---|
| EntityManager | Core interface in JPA to manage entities (CRUD, queries). Handles persistence context. |
| EntityTransaction | Manages transactions for write operations (persist, merge, remove). Must begin/commit/rollback explicitly in RESOURCE_LOCAL transactions. |
| Query / TypedQuery | Used to create and execute JPQL or SQL queries. TypedQuery<T> is type-safe. |
| Repository | Design pattern that abstracts persistence operations (CRUD and queries) into a reusable class. Encapsulates EntityManager logic. |
Relationship:
classDiagram
class EntityManager {
+persist(entity)
+merge(entity)
+remove(entity)
+find(entityClass, id)
+createQuery(query)
+getTransaction()
+close()
}
class EntityTransaction {
+begin()
+commit()
+rollback()
+isActive()
}
class Query {
+getResultList()
+getSingleResult()
+setParameter()
+executeUpdate()
}
EntityManager --> EntityTransaction : manages
EntityManager --> Query : creates
Using for:
| Method | Purpose |
|---|---|
persist(Object entity) |
Make a transient entity managed and schedule insert. |
merge(Object entity) |
Merge detached entity into current persistence context. |
remove(Object entity) |
Mark entity for deletion. |
find(Class<T> entityClass, Object primaryKey) |
Retrieve entity by primary key. |
createQuery(String jpql) |
Create JPQL query. |
getTransaction() |
Get the EntityTransaction to manage transactions. |
close() |
Close the EntityManager and release resources. |
Using for:
| Method | Purpose |
|---|---|
begin() |
Start a transaction. |
commit() |
Commit changes to the database. |
rollback() |
Rollback transaction if an error occurs. |
isActive() |
Check if transaction is active. |
Using for:
| Method | Purpose |
|---|---|
setParameter(String name, Object value) |
Bind a parameter to the query. |
getResultList() |
Return a list of results. |
getSingleResult() |
Return a single result; throws exception if none/multiple. |
executeUpdate() |
For update/delete queries. |
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package Repositories;
import Models.User;
import Utils.JPAUtil;
import jakarta.persistence.*;
import java.util.List;
public class UserRepository {
private EntityManager em;
public UserRepository() {
this.em = JPAUtil.getEntityManagerFactory().createEntityManager();
}
public List<User> getAll() {
String sql = "SELECT * FROM Users";
Query query = em.createNativeQuery(sql, User.class);
return query.getResultList();
}
public User checkUser(String username, String password) {
String sql = "SELECT * FROM Users WHERE Username = ? AND Password = ?";
try {
Query query = em.createNativeQuery(sql, User.class);
query.setParameter(1, username);
query.setParameter(2, password);
return (User) query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public void addUser(User user) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.persist(user);
tx.commit();
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
}
}
public void updateUser(User user) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.merge(user);
tx.commit();
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
}
}
public void deleteUser(int id) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
User user = em.find(User.class, id);
if (user != null) {
em.remove(user);
}
tx.commit();
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
}
}
public void close() {
if (em.isOpen()) {
em.close();
}
}
}
Create ProductRepository (Replace DALs/ProductDAO.java)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package Repositories;
import Models.Product;
import Utils.JPAUtil;
import jakarta.persistence.*;
import java.util.List;
public class ProductRepository {
private EntityManager em;
public ProductRepository() {
this.em = JPAUtil.getEntityManagerFactory().createEntityManager();
}
public List<Product> getAllProducts() {
String sql = "SELECT * FROM Products";
Query query = em.createNativeQuery(sql, Product.class);
return query.getResultList();
}
public Product getProductById(int id) {
String sql = "SELECT * FROM Products WHERE id = ?";
try {
Query query = em.createNativeQuery(sql, Product.class);
query.setParameter(1, id);
return (Product) query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public boolean createProduct(String name, double price, String description, int quantity, String img) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Product product = new Product(name, price, description, quantity, img);
em.persist(product);
tx.commit();
return true;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
return false;
}
}
public boolean updateProductById(int id, String name, double price, String description, int quantity, String img) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Product product = em.find(Product.class, id);
if (product != null) {
product.setName(name);
product.setPrice(price);
product.setDescription(description);
product.setQuantity(quantity);
product.setImage(img);
em.merge(product);
}
tx.commit();
return product != null;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
return false;
}
}
public boolean deleteProductById(int id) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Product product = em.find(Product.class, id);
if (product != null) {
em.remove(product);
}
tx.commit();
return product != null;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
e.printStackTrace();
return false;
}
}
public void close() {
if (em.isOpen()) em.close();
}
}
Replace DAOs to Repositories. Example in LoginServlet.java:
1
2
3
4
5
6
7
// Replace
UserDAO users = new UserDAO();
String uName = users.CheckUser(username, password);
// To
UserRepository userRepository = new UserRepository();
String uName = userRepository.CheckUser(username, password);
Same as another places
GOOD LUCK!!! :D