1

I have a Spring/JPA/Hibernate application that maintains state data in a mysql table. The application is dependent on that state data being initialized properly. That is, when the application initializes, I want to ensure that a known table includes two rows-- one each with two known primary key values.

The table is "JPA managed" (sorry if that term is not correct)-- I have an @Entity class that maps each row in the table to an instance of that class and a corresponding DAO class that manipulates (persists, retrieves) instances of that @Entity.

My (unsuccessful) attempt to solve this problem used an initialize() method on the DAO annotated with @PostConstruct (as well as @Transactional(read-only = false)). That method instantiates two instances of the @Entity and has calls the EntityManager to persist them (I use persist instead of merge to avoid overwriting existing state and catch the EntityExistsException that's expected if the row(s) already exist).

I've confirmed that the initialize() method is being invoked and is calling the persist(...) method on the EntityManager but the database rows are not being inserted-- I've examined the mysql statement log and the expected INSERT statements are not present.

I can't be the first person who wants to initialize data in a JPA-managed table, right? Is there a "best-practice" for doing this sort of initialization?

Thanks!

PS: Although the table is "JPA-managed" it is not created by Hibernate. The table is assumed (by the application) to already exist.

jsinnott
  • 201
  • 1
  • 9

1 Answers1

0

JPA implementations tend to delay flushing to DB until commit. Are you sure that INSERTs are not done even at commit time? Can you try flush()ing at the end of your initialize() method? Because of that delaying, flush() is needed if you want to catch some JPA exception and deal with it inside the same transaction that executes the DML.

UPDATE

As zbigniewTomczak says in his comment, initialize()should be transactional. The problem with that is that I am not sure that Spring is going to honor a @Transactional annotation in a init-method. You can try that as it is the easier option, and if it does not work, then you can try programmatic transaction management in your initialize() (either completely manual or using TransactionTemplate): Read Spring documentation about programmatic transactions

gpeche
  • 21,974
  • 5
  • 38
  • 51
  • Thanks for your answer! I'll try this... gimme five minutes :) But shouldn't the `@Transactional(...)` annotation take care of this? – jsinnott Jul 15 '14 at 23:13
  • OK (again, thanks for your answer!). The plot thickens: When I add a `flush()` call to the end of the `initialize()` method I get the following interesting exception: `javax.persistence.TransactionRequiredException: no transaction is in progress at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)` (sorry about the formatting). – jsinnott Jul 15 '14 at 23:18
  • With Hibernate and JTA transaction management you need active transaction to store changes to DB. I would recommend `@Transactional(propagation=Propagation.REQUIRES_NEW)` instead of flushing. – zbig Jul 16 '14 at 06:56
  • Thanks to you both for your answers. I'll add the suggested `propatagation` value to the existing `@Transactional(...)` annotation and see what happens. Again, thanks for your help. – jsinnott Jul 16 '14 at 13:44
  • Hi and thanks again for your help. Sadly, the simple addition of `propagation=Propagation.REQUIRES_NEW` to the `@Transactional(...)` annotation didn't solve the problem. I have, however found an alternate solution that appears to work: I've implemented the `ApplicationListener` interface as described in [this question](http://stackoverflow.com/questions/17346679/transactional-on-postconstruct-method). This appears to solve my problem. Again my thanks to you both for your help. – jsinnott Jul 16 '14 at 16:24