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
Copy file name to clipboardExpand all lines: documentation/src/main/asciidoc/introduction/Advanced.adoc
+53Lines changed: 53 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -338,6 +338,59 @@ Within a given session, our data is automatically filtered so that only rows tag
338
338
Native SQL queries are _not_ automatically filtered by tenant id; you'll have to do that part yourself.
339
339
====
340
340
341
+
[[read-only-replicas]]
342
+
=== Read-only replicas
343
+
344
+
A similar but distinct problem is accessing data held in a read-only replica of the main production database.
345
+
One way to handle this problem is to simply instantiate two instances of `SessionFactory`:
346
+
347
+
- read-only transactions use a `SessionFactory` configured to access the read-only replica, while
348
+
- other transactions use the `SessionFactory` configured to read from and write to the main database.
349
+
350
+
[CAUTION]
351
+
====
352
+
The second-level cache doesn't play well with replication, and so a `SessionFactory` with access to a read-only replica should be configured with the second-level cache disabled.
353
+
====
354
+
355
+
Alternatively, Hibernate 7.2 introduces experimental support for accessing replicas via a single instance of `SessionFactory`.
356
+
A `Session` which accesses a read-only replica must be created in a special read-only mode:
357
+
358
+
[source,java]
359
+
----
360
+
Session readOnlySession =
361
+
factory.withOptions()
362
+
.readOnly(true)
363
+
.initialCacheMode(CacheMode.IGNORE)
364
+
.openSession();
365
+
----
366
+
367
+
There are now two possibilities.
368
+
369
+
- Some JDBC drivers (MySQL) are able to automatically direct read-only sessions to the read-only replica.
370
+
In this case, there's no more work to do, since Hibernate will automatically call `Connection.setReadOnly(true)` to signal to the JDBC driver that the read-only replica may be used.
371
+
372
+
- Other drivers (Postgres, Oracle) don't feature any special support for read-only replicas, and in this case we need to supply our own custom link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html[`ConnectionProvider`] or link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/MultiTenantConnectionProvider.html[`MultiTenantConnectionProvider`] and implement link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html#getReadOnlyConnection()[`getReadOnlyConnection()`] to return a connection to the read-only replica.
373
+
374
+
Notice that we created the read-only session with link:{doc-javadoc-url}/org/hibernate/CacheMode.html#IGNORE[`CacheMode.IGNORE`], indicating that access to the read-only replica should <<second-level-cache-management,bypass the second-level cache>>.
375
+
There's two different phenomena we need to consider here:
376
+
377
+
1. A read-only replica might contain stale data which has already been updated or deleted from the main database and invalidated in the second-level cache.
378
+
A read-only session might read this stale data and recache it, exposing the stale data to subsequent sessions.
379
+
Use of `CacheMode.GET` in a read-only session prevents this phenomenon.
380
+
381
+
2. A session might read data which has not yet been replicated from the main database and add it to the second-level cache.
382
+
If a read-only session reads this data from the cache, it might fail to resolve references to other data which has not yet been replicated.
383
+
Use of `CacheMode.PUT` in a read-only session prevents this phenomenon.
384
+
385
+
Use of `CacheMode.IGNORE` in a read-only session prevents both phenomena.
386
+
387
+
[CAUTION]
388
+
====
389
+
The first issue is objectively more serious than the second, and the second issue can often be avoided by careful programming by someone _who really understands what they're doing_.
390
+
We do not, therefore, require the use of `CacheMode.IGNORE`, but we strongly encourage the use of _at least_ `CacheMode.GET` in every read-only session.
0 commit comments