Hibernate 8 + Jakarta Persistence 4: EntityAgent and stateless sessions demo

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b7jUQrypvpE1ix1k7V
This commit is contained in:
asmhatre
2026-11-14 01:34:34 +05:30
co-authored by Claude Sonnet 5.5
commit 453fad0ee7
29 changed files with 1109 additions and 0 deletions
@@ -0,0 +1,13 @@
EntityManager: find, edit title, commit (2 statements)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
select version from final table (update book set price=?,publisher_id=?,title=?,version=?,views=? where isbn=? and version=?)
title in database afterwards: Changed via EntityManager
EntityAgent: get, edit title, commit (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
title in database afterwards: Book 2
EntityAgent: get, edit title, update(book), commit (2 statements)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
select version from final table (update book set version=case when price is distinct from ? or publisher_id is distinct from ? or title is distinct from ? then ? else version end,price=?,publisher_id=?,title=?,views=? where isbn=? and version=?)
title in database afterwards: Changed via EntityAgent + update()
+17
View File
@@ -0,0 +1,17 @@
agent.find(missing) -> null
agent.get(missing) -> EntityNotFoundException
EntityAgent, same id twice in one transaction:
same instance? false
SQL (2 statements)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
EntityManager, same id twice in one transaction:
same instance? true
SQL (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=?
agent.getMultiple(3 ids) returned 3 books
SQL (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn in (?,?,?)
+12
View File
@@ -0,0 +1,12 @@
agent.get(Book): publisher initialized? false
book.publisher.getName() before fetch -> LazyInitializationException
agent.fetch(book.publisher) -> getName() = Manning
same object as book.publisher? true, initialized now? true
reading the public field p.name instead -> null
SQL (1 statement)
select p1_0.id,p1_0.name from publisher p1_0 where p1_0.id=?
agent.get(Publisher): books collection initialized? false
agent.fetch(publisher.books) -> 3 books
SQL (1 statement)
select b1_0.publisher_id,b1_0.isbn,b1_0.price,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.publisher_id=?
+13
View File
@@ -0,0 +1,13 @@
EntityManager.persist x 5000 in one transaction
entities held in the persistence context at the end: 5000
entity inserts: 5000 statements prepared: 1
EntityAgent.insert x 5000 in one transaction
entities held anywhere: 0 (a StatelessSession has no persistence context)
entity inserts: 5000 statements prepared: 5000
EntityAgent.insertMultiple(list of 5000)
entity inserts: 5000 statements prepared: 1
publisher.id before insert: null
publisher.id after insert: 1 (insert() itself returns void)
+45
View File
@@ -0,0 +1,45 @@
=== H2 ===
get(Book.class, "978-1", OPTIMISTIC)
right after get() (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=? for update
during commit (0 statements)
version before: 0, after: 0
get(Book.class, "978-1", OPTIMISTIC_FORCE_INCREMENT)
right after get() (2 statements)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=? for update
update book set version=? where isbn=? and version=?
during commit (0 statements)
version before: 0, after: 1
get(Book.class, "978-1", PESSIMISTIC_WRITE)
right after get() (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=? for update
during commit (0 statements)
version before: 1, after: 1
get(Book.class, "978-1", PESSIMISTIC_FORCE_INCREMENT)
right after get() (2 statements)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=? for update
update book set version=? where isbn=? and version=?
during commit (0 statements)
version before: 1, after: 2
=== HSQLDB ===
get(Book.class, "978-1", OPTIMISTIC)
FAILED: org.hibernate.HibernateException: Stateless optimistic locking requires transaction-long row protection; no strategy established for HSQLDialect:2:LOCKING
get(Book.class, "978-1", OPTIMISTIC_FORCE_INCREMENT)
FAILED: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "owner" is null
get(Book.class, "978-1", PESSIMISTIC_WRITE)
right after get() (1 statement)
select b1_0.isbn,b1_0.price,b1_0.publisher_id,b1_0.title,b1_0.version,b1_0.views from book b1_0 where b1_0.isbn=? for update
during commit (0 statements)
version before: 0, after: 0
get(Book.class, "978-1", PESSIMISTIC_FORCE_INCREMENT)
FAILED: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "owner" is null
+3
View File
@@ -0,0 +1,3 @@
loaded: version=0 views=0
after update() that changed only views: version=0 views=42
after update() that changed title: version=1 views=42
@@ -0,0 +1,5 @@
entity mapping through EntityAgent: 3 rows, first = 978-1 / Book 1 / 10.00
entity mapping through EntityManager: 3 rows, managed by the persistence context? true
constructor mapping -> BookSummary[title=Book 1, price=10.00]
tuple mapping -> (978-1, 0)
+11
View File
@@ -0,0 +1,11 @@
createEntityAgent() returns: org.hibernate.internal.StatelessSessionImpl
instanceof org.hibernate.StatelessSession: true
upsert(theme=dark) on an existing row, upsert(language=en) on a new row (2 statements)
merge into setting as t using (select cast(? as varchar(255)) name,cast(? as varchar(255)) val) as s on (t.name=s.name) when not matched then insert (name,val) values (s.name,s.val) when matched then update set val=s.val
merge into setting as t using (select cast(? as varchar(255)) name,cast(? as varchar(255)) val) as s on (t.name=s.name) when not matched then insert (name,val) values (s.name,s.val) when matched then update set val=s.val
theme -> dark
language -> en
insert() with an existing primary key -> jakarta.persistence.EntityExistsException
find() after delete() -> null
@@ -0,0 +1,12 @@
=== H2 ===
EntityAgent.update(stale book) -> org.hibernate.HibernateException: The database returned no natively generated values : com.ankurm.agent.Book
EntityManager.merge(stale book) -> jakarta.persistence.OptimisticLockException
EntityAgent.update(row not in db) -> org.hibernate.HibernateException: The database returned no natively generated values : com.ankurm.agent.Book
EntityAgent.upsert(new versioned) -> org.hibernate.HibernateException: The database returned no natively generated values : com.ankurm.agent.Book
=== HSQLDB ===
EntityAgent.update(stale book) -> jakarta.persistence.OptimisticLockException
EntityManager.merge(stale book) -> jakarta.persistence.OptimisticLockException
EntityAgent.update(row not in db) -> jakarta.persistence.OptimisticLockException
EntityAgent.upsert(new versioned) -> jakarta.persistence.OptimisticLockException