You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`EntityTransaction` also provides a way to set the transaction to rollback-only mode:
228
+
229
+
[source,java]
230
+
----
231
+
entityManager.getTransaction().setRollbackOnly();
232
+
----
233
+
234
+
A transaction in rollback-only mode will be rolled back when it completes.
235
+
217
236
[[persistence-operations]]
218
237
=== Operations on the persistence context
219
238
@@ -256,6 +275,8 @@ On the other hand, except for `getReference()`, the following operations all res
256
275
| Obtain a persistent object given its type and its id
257
276
| `find(Class,Object,LockModeType)`
258
277
| Obtain a persistent object given its type and its id, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>
278
+
| `find(EntityGraph,Object)`
279
+
| Obtain a persistent object given its id and an `EntityGraph` specifying its type and associations which should be eagerly fetched
259
280
| `getReference(Class,id)`
260
281
| Obtain a reference to a persistent object given its type and its id, without actually loading its state from the database
261
282
| `getReference(Object)`
@@ -264,7 +285,7 @@ On the other hand, except for `getReference()`, the following operations all res
264
285
| Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database
265
286
| `refresh(Object,LockModeType)`
266
287
| Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>
267
-
| `lock(Object,LockModeType)`
288
+
| `lock(Object,LockModeType)`
268
289
| Obtain an <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock>> on a persistent object
269
290
|===
270
291
@@ -280,6 +301,46 @@ The persistence context is fragile.
280
301
If you receive an exception from Hibernate, you should immediately close and discard the current session. Open a new session if you need to, but throw the bad one away first.
281
302
====
282
303
304
+
Four of these operations accept _options_, allowing influence over their behavior.
305
+
306
+
[%breakable,cols="50,~"]
307
+
|===
308
+
| Method name and parameters | Effect
309
+
310
+
| `find(Class,Object,FindOption...)`
311
+
| Obtain a persistent object given its type and its id, using the specified options
312
+
| `find(EntityGraph,Object,FindOption...)`
313
+
| Obtain a persistent object given its id and an `EntityGraph` specifying its type and associations which should be eagerly fetched, using the specified options
314
+
| `refresh(Object,LockModeType,RefreshOption...)`
315
+
| Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>, using the specified options
316
+
| `lock(Object,LockModeType,LockOption...)`
317
+
| Obtain an <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock>> on a persistent object, using the specified options
318
+
|===
319
+
320
+
For example, JPA provides the `Timeout` class which is a `FindOption`, a `RefreshOption`, and a `LockOption`.
321
+
322
+
[source,java]
323
+
----
324
+
var book = entityManger.find(Book.class, isbn, Timeout.ms(100), CacheStoreMode.BYPASS);
325
+
----
326
+
327
+
Finally, the Hibernate `Session` offers the following method, which is capable of efficiently loading multiple entity instances in parallel:
But the static methods of the link:{doc-javadoc-url}org/hibernate/Hibernate.html[`Hibernate`] class let us do a lot more, and it's worth getting a bit familiar with them.
444
+
Similarly, `PersistenceUnitUtil.load()` force-fetches a proxy or collection:
384
445
385
-
Of particular interest are the operations which let us work with unfetched collections without fetching their state from the database.
386
-
For example, consider this code:
446
+
[source,java]
447
+
----
448
+
Book book = session.find(Book.class, bookId); // fetch just the Book, leaving authors unfetched
Again, `Hibernate.initialize()` is slightly more convenient:
387
453
388
454
[source,java]
389
455
----
390
456
Book book = session.find(Book.class, bookId); // fetch just the Book, leaving authors unfetched
391
-
Author authorRef = session.getReference(Author.class, authorId); // obtain an unfetched proxy
392
-
boolean isByAuthor = Hibernate.contains(book.getAuthors(), authorRef); // no fetching
457
+
Hibernate.initialize(book.getAuthors()); // fetch the Authors
393
458
----
394
459
395
-
This code fragment leaves both the set `book.authors` and the proxy `authorRef` unfetched.
460
+
On the other hand, the above code is very inefficient, requiring two trips to the database to obtain data that could in principle be retrieved with just one query.
396
461
397
-
Finally, `Hibernate.initialize()` is a convenience method that force-fetches a proxy or collection:
462
+
The static methods of the link:{doc-javadoc-url}org/hibernate/Hibernate.html[`Hibernate`] class let us do a lot more, and it's worth getting a bit familiar with them.
463
+
Of particular interest are the operations which let us work with unfetched collections without fetching their state from the database.
464
+
For example, consider this code:
398
465
399
466
[source,java]
400
467
----
401
468
Book book = session.find(Book.class, bookId); // fetch just the Book, leaving authors unfetched
402
-
Hibernate.initialize(book.getAuthors()); // fetch the Authors
469
+
Author authorRef = session.getReference(Author.class, authorId); // obtain an unfetched proxy
470
+
boolean isByAuthor = Hibernate.contains(book.getAuthors(), authorRef); // no fetching
403
471
----
404
472
405
-
But of course, this code is very inefficient, requiring two trips to the database to obtain data that could in principle be retrieved with just one query.
473
+
This code fragment leaves both the set `book.authors` and the proxy `authorRef` unfetched.
406
474
407
475
It's clear from the discussion above that we need a way to request that an association be _eagerly_ fetched using a database `join`, thus protecting ourselves from the infamous N+1 selects.
408
476
One way to do this is by passing an `EntityGraph` to `find()`.
@@ -413,24 +481,20 @@ One way to do this is by passing an `EntityGraph` to `find()`.
413
481
When an association is mapped `fetch=LAZY`, it won't, by default, be fetched when we call the `find()` method.
414
482
We may request that an association be fetched eagerly (immediately) by passing an `EntityGraph` to `find()`.
415
483
416
-
The JPA-standard API for this is a bit unwieldy:
417
-
418
484
[source,java]
419
485
----
420
486
var graph = entityManager.createEntityGraph(Book.class);
421
487
graph.addSubgraph(Book_.publisher);
422
-
Book book = entityManager.find(Book.class, bookId, Map.of(SpecHints.HINT_SPEC_FETCH_GRAPH, graph));
488
+
Book book = entityManager.find(graph, bookId);
423
489
----
424
490
425
-
This is untypesafe and unnecessarily verbose.
426
-
Hibernate has a better way:
427
-
428
-
[source,java]
429
-
----
430
-
var graph = session.createEntityGraph(Book.class);
431
-
graph.addSubgraph(Book_.publisher);
432
-
Book book = session.byId(Book.class).withFetchGraph(graph).load(bookId);
433
-
----
491
+
//
492
+
// [source,java]
493
+
// ----
494
+
// var graph = session.createEntityGraph(Book.class);
495
+
// graph.addSubgraph(Book_.publisher);
496
+
// Book book = session.byId(Book.class).withFetchGraph(graph).load(bookId);
497
+
// ----
434
498
435
499
This code adds a `left outer join` to our SQL query, fetching the associated `Publisher` along with the `Book`.
436
500
@@ -441,10 +505,17 @@ We may even attach additional nodes to our `EntityGraph`:
441
505
var graph = session.createEntityGraph(Book.class);
// Book book = session.byId(Book.class).withFetchGraph(graph).load(bookId);
517
+
// ----
518
+
448
519
This results in a SQL query with _four_ ``left outer join``s.
449
520
450
521
[NOTE]
@@ -460,8 +531,13 @@ JPA specifies that any given `EntityGraph` may be interpreted in two different w
460
531
Any association not belonging to the entity graph is proxied and loaded lazily only if required.
461
532
- A _load graph_ specifies that the associations in the entity graph are to be fetched in addition to the associations mapped `fetch=EAGER`.
462
533
534
+
An `EntityGraph` passed directly to `find()` is always interpreted as a load graph.
535
+
536
+
[TIP]
537
+
====
463
538
You're right, the names make no sense.
464
539
But don't worry, if you take our advice, and map your associations `fetch=LAZY`, there's no difference between a "fetch" graph and a "load" graph, so the names don't matter.
540
+
====
465
541
466
542
[NOTE]
467
543
====
@@ -580,6 +656,13 @@ A second way to reduce the cost of flushing is to load entities in _read-only_ m
580
656
- `SelectionQuery.setReadOnly(true)` specifies that every entity returned by a given query should be loaded in read-only mode, and
581
657
- `Session.setReadOnly(Object, true)` specifies that a given entity already loaded by the session should be switched to read-only mode.
582
658
659
+
Hibernate's `ReadOnlyMode` is a custom `FindOption`:
660
+
661
+
[source,java]
662
+
----
663
+
var book = entityManager.find(Book.class, isbn, ReadOnlyMode.READ_ONLY);
664
+
----
665
+
583
666
It's not necessary to dirty-check an entity instance in read-only mode.
584
667
585
668
[[queries]]
@@ -1224,6 +1307,11 @@ Therefore, Hibernate has some APIs that streamline certain more complicated look
1224
1307
| `byMultipleIds()` | Lets us load a _batch_ of ids at the same time
1225
1308
|===
1226
1309
1310
+
[WARNING]
1311
+
====
1312
+
Since the introduction of `FindOption` in JPA 3.2, `byId()` is now much less useful.
1313
+
====
1314
+
1227
1315
Batch loading is very useful when we need to retrieve multiple instances of the same entity class by id:
1228
1316
1229
1317
[source,java]
@@ -1270,22 +1358,36 @@ Notice that this code fragment is completely typesafe, again thanks to the <<met
1270
1358
=== Interacting directly with JDBC
1271
1359
1272
1360
From time to time we run into the need to write some code that calls JDBC directly.
1273
-
Unfortunately, JPA offers no good way to do this, but the Hibernate `Session` does.
1361
+
The `EntityManager` now offers a convenient way to do this:
The `Connection` passed to the work is the same connection being used by the session, and so any work performed using that connection occurs in the same transaction context.
1373
+
To return a value, use `callWithConnection()` instead of `runWithConnection()`.
1374
+
1375
+
The Hibernate `Session` has an older, slightly simpler API:
If the work returns a value, use `doReturningWork()` instead of `doWork()`.
1288
1388
1389
+
The `Connection` passed to the work is the same connection being used by the session, and so any work performed using that connection occurs in the same transaction context.
1390
+
1289
1391
[TIP]
1290
1392
====
1291
1393
In a container environment where transactions and database connections are managed by the container, this might not be the easiest way to obtain the JDBC connection.
0 commit comments