5

I am developping a JPA application (with hibernate), and I am fighting with the AutoFlush feature.

By default, whenever we process a query on any entity, the complete EntityManager is flushed. This is ok in most cases : We want JPA to process queries against an up-to-date DB.

However, it happens that we also store some functional parameters in our DB. This is completely separated from our core business model, and we don't want that selecting parameters we flushed the EM : Fetch of parameters can happen quite deep in the process and we loose the control of flushing EM when we know it;as ok.

Indeed, this causes some DB constraint exception : The data model is not consistent yet (in the middle of a process), and selecting a parameter forces the flush of this data model.

I am considering adding a second entityManager, just of the parameters, but I find it a bit overkill.

Could it be solved more easily ? With isolation level on the Parameters DAO, so that Parameters are processed in a separate transaction ?

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
Raphael Jolivet
  • 3,940
  • 5
  • 36
  • 56

2 Answers2

3

This can be solved with JTA transactions, but you need a JTA transaction manager. If you are running in a Java EE application server than you already have JTA support. If you run a Spring based application you need to include a stand-alone TM, like Bitronix.

JTA then allows you to enlist multiple connections even for the same DB (but with multiple data sources from the same thread) in a single global transaction. So you entity manager will enlist one connection and then you could open a new connection from your XA connection pool (provided by your JTA transaction manager, like Bitronix) and save the functional parameters.

Those 2 enlisted connections will be isolated, so changes in one won't be available in the second until after the transaction is committed.

If the functional parameters don't need to be saved through JPA, it's easier to use Spring JDBC for this task. Otherwise you need two entity managers and that will complicate your settings even more.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • I am really curios how you "could open a new connection from your XA connection pool", could you give more details on that please?. PS: It could be an interesting solution, but by far not using standard APIs. – V G May 27 '14 at 13:04
  • Check my [HibernateSQLStatementCountTest](https://github.com/vladmihalcea/vladmihalcea.wordpress.com/blob/master/hibernate-facts/src/test/java/com/vladmihalcea/HibernateSQLStatementCountTest.java). It enlists 2 data sources: testDataSource and otherDataSource in the same transaction for the same DB, each one with it's own connection. DEBUG [main]: b.t.t.Preparer - preparing resource an XAResourceHolderState with uniqueName=otherDataSource DEBUG [main]: b.t.t.Preparer - preparing resource an XAResourceHolderState with uniqueName=testDataSource – Vlad Mihalcea May 27 '14 at 14:32
  • That is not what you described in your answer: on github you have two different `DataSource`s and in your answer you are talking about retrieving two connections for the same `DataSource`. – V G May 27 '14 at 15:03
  • I updated my response. The TM will bind the current thread to the same connections even if we aggressively release it after each statement. So one DS is one XS resource, but for one thread you always get the same connection within one Tx. But you can spawn multiple DS even for the same DB/Schema and then you could do the trick. – Vlad Mihalcea May 27 '14 at 15:10
  • 1
    This solution with multiple `DataSource`s is IMHO worse than using two `EntityManager`. One argument is: you work on a lower level than JPA and another is: you have to deal with non-EE-standard calls to Bitronix JTA manager. – V G May 27 '14 at 15:27
  • So you say that 2 resource local tx are better. What if one succeeds and the other fails? No ACID in this case, right? – Vlad Mihalcea May 27 '14 at 15:36
  • No. My first case explains 2 solutions within an JTA environment. The second case (RESOURCE-LOCAL environment) is only for the case the OP is ALREADY in that environment (with this, the disadvantages of the RESOURCE-LOCAL EntityManager will be inherited (you are right, there is that new bad scenario)). PS: I reordered the ideas. – V G May 27 '14 at 16:17
1

I. If you use JTA:

  1. Try using a new transaction in the ParametersDAO. This way your managed entities in the outer service will not be managed in the inned DAO (IMHO!). The disadvantage is that when your ParametersDAO returns, the transaction will commit (if that is not desired, you could use a Statefull EJB, but this one seems like an overkill to me).
  2. Otherwise, having a second EntityManager does not seem such an overkill to me.

II. If you use RESOURCE-LOCAL:

If you are in an Application-Managed environment (transaction-type="RESOURCE_LOCAL"), simply get another EntityManager from the EntityManagerFactory (similarly with having a second EntityManager).

V G
  • 18,822
  • 6
  • 51
  • 89