Skip to content

fix(GH-225): Configure shared entity manager for multiple data sources example #228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 15, 2019

Conversation

igdianov
Copy link
Collaborator

@igdianov igdianov commented Dec 15, 2019

Fixes #225

As described in https://docs.jboss.org/hibernate/core/4.0/hem/en-US/html/transactions.html#transactions-basics-issues Never use the anti-patterns entitymanager-per-user-session or entitymanager-per-application (of course, there are rare exceptions to this rule, e.g. entitymanager-per-application might be acceptable in a desktop application, with manual flushing of the persistence context). Note that some of the following issues might also appear with the recommended patterns, make sure you understand the implications before making a design decision:

  • An entity manager is not thread-safe. Things which are supposed to work concurrently, like HTTP requests, session beans, or Swing workers, will cause race conditions if an EntityManager instance would be shared. If you keep your Hibernate EntityManager in your HttpSession (discussed later), you should consider synchronizing access to your Http session. Otherwise, a user that clicks reload fast enough may use the same EntityManager in two concurrently running threads. You will very likely have provisions for this case already in place, for other non-threadsafe but session-scoped objects.

  • An exception thrown by the Entity Manager means you have to rollback your database transaction and close the EntityManager immediately (discussed later in more detail). If your EntityManager is bound to the application, you have to stop the application. Rolling back the database transaction doesn't put your business objects back into the state they were at the start of the transaction. This means the database state and the business objects do get out of sync. Usually this is not a problem, because exceptions are not recoverable and you have to start over your unit of work after rollback anyway.

  • The persistence context caches every object that is in managed state (watched and checked for dirty state by Hibernate). This means it grows endlessly until you get an OutOfMemoryException, if you keep it open for a long time or simply load too much data. One solution for this is some kind batch processing with regular flushing of the persistence context, but you should consider using a database stored procedure if you need mass data operations. Some solutions for this problem are shown in Chapter 7, Batch processing. Keeping a persistence context open for the duration of a user session also means a high probability of stale data, which you have to know about and control appropriately.

Therefore, it is recommended to instrument GraphQL JPA Query Schema Builder with it is own shared EntityManager proxy that uses it's own database connection pool to isolate it from any Mutation side that may use same transaction.

With Spring, this can be achieved with @PersistentContext annotation when autowiring EntityManager instance or with SharedEntityManagerBean if there is a need to create multiple data sources for different persistent units.

With shared EntityManager proxy enabled, each query request will create its own instance of EntityManager inside new transaction to execute query, and then automatically closes EntityManager instance to release any resources when transaction request is executed.

@igdianov igdianov self-assigned this Dec 15, 2019
@codecov
Copy link

codecov bot commented Dec 15, 2019

Codecov Report

Merging #228 into master will increase coverage by 0.09%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #228      +/-   ##
============================================
+ Coverage     73.48%   73.58%   +0.09%     
- Complexity      845      848       +3     
============================================
  Files            49       49              
  Lines          3651     3657       +6     
  Branches        606      606              
============================================
+ Hits           2683     2691       +8     
+ Misses          704      703       -1     
+ Partials        264      263       -1
Impacted Files Coverage Δ Complexity Δ
...phql/jpa/query/schema/impl/GraphQLJpaExecutor.java 100% <ø> (ø) 3 <0> (ø) ⬇️
.../example/starwars/StarwarsSchemaConfiguration.java 100% <100%> (ø) 5 <1> (+1) ⬆️
.../query/example/books/BooksSchemaConfiguration.java 100% <100%> (ø) 5 <1> (+1) ⬆️
.../graphql/jpa/query/introspection/Constructors.java 82% <0%> (+4%) 15% <0%> (+1%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 38bfb17...2d0eb75. Read the comment docs.

@igdianov igdianov merged commit b235ee8 into master Dec 15, 2019
@igdianov igdianov deleted the fix-GH-225-shared-entity-manager branch December 15, 2019 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use shared entity manager for multiple data sources example
1 participant