A complete, step-by-step guide — from installation to a working persistent bookstore application.
Use ← → arrow keys or the buttons below to navigate
Book entity to a database tableRuntime + compiler for all Java code
IDE with built-in JPA & GlassFish support
Database server + visual query tool
Four components must be installed before you write a single line of code. We'll do them in the right order.
JAVA_HOME points to your JDK folder (e.g., C:\Program Files\Eclipse Adoptium\jdk-21).
brew install --cask temurin@21
C:\servers\glassfish7)brew install --cask mysqlworkbenchIf your project uses Maven (pom.xml), add this dependency — Maven downloads the driver automatically:
glassfish7/glassfish/domains/domain1/lib/ for server-managed connections.
Before writing JPA code you need a database, a schema, a table, and the correct project structure in NetBeans.
bookstoredb, charset utf8mb4, collation utf8mb4_unicode_cibookstoredb in the result. Keep this connection open — you'll use Workbench to inspect data throughout the project.
| Column | Type | Notes |
|---|---|---|
id | INT | Auto PK — maps to @Id @GeneratedValue |
title | VARCHAR(255) | Required |
author | VARCHAR(150) | Required |
isbn | VARCHAR(20) | Unique constraint |
price | DECIMAL(8,2) | Maps to BigDecimal |
stock_qty | INT | Maps to int |
hibernate.hbm2ddl.auto = create in persistence.xml.
pom.xml file — your project's shopping list of dependencies.
App.java inside com.bookstore.Main.java later.
| Field | What to enter |
|---|---|
| Project Name | BookstoreJPA |
| Project Location | Any folder (e.g. your Desktop) |
| Group Id | com.bookstore |
| Artifact Id | BookstoreJPA (auto-filled) |
| Version | Leave as 1.0-SNAPSHOT |
.java files. The name com.bookstore.entity tells Java to create nested folders: com/ → inside it bookstore/ → inside it entity/. Keeping entity classes, DAO classes, and the main class in separate packages is standard professional practice.
com.bookstore.entitycom.bookstore.entitycom.bookstore.daocom.bookstore.daocom.bookstorecom.bookstore.daocom.bookstore.entity
persistence.xml inside a folder named META-INF on the Java classpath. In a Maven project the classpath root is src/main/resources/, so you must create the folder there — not inside src/main/java/.
META-INFpersistence (NetBeans adds .xml)src/main/resources/META-INF/persistence.xml — this file tells JPA which database to connect to and which provider (Hibernate) to use.
YourPasswordHere with your actual root password. Never commit passwords to a public repository.
useSSL=false&serverTimezone=UTC& character must be written as & — a bare & will cause the error:Now the fun part — entity class, DAO, and a main class that performs full CRUD operations on the bookstore database.
src/main/java/com/bookstore/entity/Book.java
| Annotation | Purpose |
|---|---|
@Entity | Marks class as JPA entity |
@Table | Maps to table name books |
@Id | Primary key field |
@GeneratedValue | Auto-increment PK |
@Column | Customise column constraints |
src/main/java/com/bookstore/dao/BookDAO.java — wraps all JPA calls so the rest of your code never touches EntityManager directly.
src/main/java/com/bookstore/Main.java
Main.java → Run File (or press F6)useSSL=false is in the JDBC URL
Book → books (via @Table(name="books")).stockQty → stock_qty (via @Column(name="stock_qty")).| Error / Symptom | Likely Cause | Fix |
|---|---|---|
Communications link failure |
MySQL not running or wrong port | Start MySQL service; check port is 3306 in JDBC URL |
Access denied for user 'root' |
Wrong password in persistence.xml | Confirm password; consider creating a dedicated DB user |
Unknown database 'bookstoredb' |
Database not created yet | Run CREATE DATABASE bookstoredb in Workbench |
No Persistence provider found |
Hibernate JARs not in classpath | Run Maven → Clean & Build to re-download deps |
Table 'books' doesn't exist |
hbm2ddl.auto not set to create/update | Set hibernate.hbm2ddl.auto=update in persistence.xml |
ClassNotFoundException: com.mysql.cj... |
Connector/J not on classpath | Add mysql-connector-j dependency to pom.xml; rebuild |
| Entities saved but IDs are 0 | Transaction not committed | Ensure em.getTransaction().commit() is called |
bookstoredb schema createdbooks table createdpersistence.xml in META-INFBook.java entity createdBookDAO.java with CRUD methodsMain.java runs without errorsGenerationType.IDENTITY mean in @GeneratedValue?EntityManager method saves a new entity to the database?em.merge(entity)em.persist(entity)em.save(entity)em.insert(entity)persistence.xml be placed in a Maven project?src/main/java/META-INF/src/main/java/src/main/resources/META-INF/src/META-INF/hibernate.auto_schemahibernate.hbm2ddl.autohibernate.schema.updatejakarta.persistence.ddl@NamedQuery. They are parsed once at startup — more efficient and easier to maintain.
category_id foreign key column to the books table automatically when hbm2ddl.auto=update.
Application code creates entity objects and calls DAO methods
DAO opens an EM, begins a transaction, calls persist/merge/remove
The JPA provider generates INSERT/UPDATE/DELETE/SELECT SQL
Data is persisted in the books table — visible in Workbench
| Concept | What It Is | In Our Project |
|---|---|---|
| JPA | Standard API for ORM in Java/Jakarta EE | The annotations + EntityManager we use |
| Hibernate | The JPA provider (implementation) | Declared in pom.xml; does the SQL work |
| Entity | A Java class mapped to a DB table | Book.java ← → books table |
| EntityManager | JPA's API for DB operations | Used inside BookDAO to persist/find/merge/remove |
| Persistence Unit | Named config block in persistence.xml | BookstorePU — references DB + entity class |
| JPQL | Object-oriented query language for JPA | SELECT b FROM Book b WHERE b.author = :a |
| CRUD | Create, Read, Update, Delete operations | persist / find / merge / remove in BookDAO |
| DAO | Data Access Object pattern | BookDAO.java — isolates DB logic |
bookstoredb and books table in Workbenchpom.xmlBook.java, BookDAO.java, Main.javapublishYear (int) field to BookfindByYear(int year) JPQL method to BookDAO@NamedQueryCategory entity with a @ManyToOne relationship to BookCategoryDAO with its own CRUD methodsBookstoreMenu class that loops on a simple text menu (add/list/search/exit) so users can interact with the bookstore from the console.
Next: Week 3 — Relationships, Cascading, and Jakarta EE Web Tier
Book.java · BookDAO.java · Main.java · persistence.xml · pom.xml
@Entity, @Id, @Column, EntityManager, JPQL, CRUD, DAO pattern
We will add Customer and Address entities to the existing BookstoreJPA project, covering three lab requirements: JPQL named queries, lifecycle callbacks, and entity listeners.
BookstoreJPA project. The persistence.xml and pom.xml only need small additions.
com.bookstore.listener → Finish.java file by right-clicking the correct package → New → Java Classpersistence.xmlCustomer entity will satisfy all three lab projects at once — named queries (P1), callback methods (P2), and external listeners (P3) are all declared on the same class.
src/main/java/com/bookstore/entity/Address.java| Column | Type |
|---|---|
id | BIGINT PK AUTO_INCREMENT |
street1 | VARCHAR(255) |
city | VARCHAR(255) |
zipcode | VARCHAR(255) |
country | VARCHAR(255) |
Customer entity has a @ManyToOne field pointing to Address.
Hibernate adds an address_id foreign key column to the customers table automatically.
Customer, you must either persist the Address first,
or add cascade = CascadeType.PERSIST to the @ManyToOne annotation on Customer.
We use cascade in this project.
src/main/java/com/bookstore/entity/Customer.java — this one class satisfies all three lab projects.| Annotation | Meaning |
|---|---|
@Transient | Field exists in Java but is not stored in DB |
@Temporal | Tells JPA how to store a java.util.Date (DATE / TIMESTAMP) |
@ManyToOne | Many customers can share one address |
@JoinColumn | Names the FK column (address_id) in customers table |
cascade = PERSIST | Saves the Address automatically when the Customer is saved |
@NamedQuery | Pre-compiled JPQL (uses entity/field names) |
@NamedNativeQuery | Pre-compiled raw SQL (uses table/column names) |
@EntityListeners | Registers external listener classes for lifecycle events |
src/main/java/com/bookstore/listener/CustomerValidator.java@EntityListeners. Listeners are preferred because they keep business logic out of the entity.
void validate(Customer c).src/main/java/com/bookstore/listener/CustomerAgeListener.java| Annotation | Fires |
|---|---|
@PrePersist | Before em.persist() |
@PostPersist | After INSERT committed to DB |
@PreUpdate | Before em.merge() / dirty flush |
@PostUpdate | After UPDATE committed to DB |
@PreRemove | Before em.remove() |
@PostRemove | After DELETE committed to DB |
@PostLoad | After entity loaded from DB (find / query) |
age is marked @Transient so it is never saved to the database.
But every time a Customer is loaded from the DB, @PostLoad fires and recalculates
the current age from the stored dateOfBirth — always up to date.
src/main/java/com/bookstore/dao/CustomerDAO.javasrc/main/resources/META-INF/persistence.xml and add the two new
<class> lines highlighted below.
addresses and customers tables in MySQL when you run the project. No SQL needed.
src/main/java/com/bookstore/Week4Main.java — right-click this file → Run File to testage column in customers table — it is @Transientcustomers.address_id FK column links to addresses.idCustomer + Address entities, @NamedQuery (JPQL), @NamedNativeQuery (SQL)
@Transient age, @PrePersist validate(), @PostLoad calculateAge()
External listener classes, @EntityListeners, same events but decoupled