Sto utilizzando Hibernate Envers per mantenere la cronologia degli oggetti. In alcuni punti vogliamo catturare un'istantanea dello stato del grafico dell'oggetto - e possiamo farlo conoscendo la corrispondente revisione di Envers che poi memorizziamo su un record di controllo.Come forzare Hibernate Envers a eseguire il commit di una revisione all'interno di un metodo Spring @Transactional
Tuttavia abbiamo un problema. L'oggetto genitore viene aggiornato all'interno della stessa transazione in cui creiamo e memorizziamo il suo record di controllo figlio, completo con la revisione di Envers. Siamo in grado di ottenere l'ultima revisione:
Number revision = reader.getRevisionNumberForDate(new Date(Long.MAX_VALUE));
o creare una nuova revisione:
Number revision = reader.getCurrentRevision(DefaultRevisionEntity.class, true).getId();
e utilizzare, ma il commettere del genitore accade sempre dopo. Ed è quando Envers incrementa la revisione. Quindi la revisione che dobbiamo effettivamente fare riferimento nel record di controllo è sempre superiore al valore memorizzato. Nel caso più semplice, si ottiene e conservare revisione N ma la versione genitore abbiamo bisogno è memorizzato come N + 1.
Il riferimento lettore AuditReader può essere ottenuto con:
JpaTransactionManager transactionManager; // injected
EntityManagerFactory emf = transactionManager.getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
AuditReader reader = AuditReaderFactory.get(entityManager);
Stiamo utilizzando Spring 3 @ Annotazioni transazionali e Hibernate 4.2.
Minimal grafico classe:
Parent.class
int version // for hibernate optimistic locking
String revisionName
List<AuditChild> audits
AuditChild.class
int enversRevision // use to retrieve previous graphs of parent
Ho provato numerosi approcci per forzare il commit di un genitore che si verifichi prima, tra i quali:
- Splitting il codice su più metodi con @Transactional (propagation = Propagation.REQUIRES_NEW)
- Invocazione esplicita di entityManager.flush();
Tutto ciò che ho provato non ha avuto alcun effetto o causato altri problemi. Sarei felice di sapere delle soluzioni che hanno funzionato per gli altri. Grazie.
Il numero di revisione deve essere univoco per una transazione, sei sicuro che 'reader.getCurrentRevision (DefaultRevisionEntity.class, true) .getId()' non funziona?Dovresti avere bisogno di fare riferimento alla revisione "corrente" per la transazione corrente. – adamw
@adamw Sì, ciò crea una nuova revisione. Tuttavia, quando la mia transazione di inclusione è stata confermata, la revisione effettiva delle righe di aggiornamento pertinenti nella tabella * _AUD è> n (n + 1 quando nessun altro aggiornamento al database si sovrappone a questo tx). Quindi l'Id sull'oggetto restituito da 'getCurrentRevision()' non era quello applicato quando è stato eseguito il commit del Tx corrente. La mia soluzione consiste nel creare una revisione fittizia (-1) e in una seconda transazione per rileggere e aggiornare il riferimento di revisione. (Ambiente: Hibernate Envers 4.2, Spring 3.2 @ Transazioni annotate transazionali, DB2 9.1). – user598656
Hmm, beh se chiami getCurrentRevision() in un TX dovresti ottenere la revisione per quella transazione. Avete qualche flush() in mezzo? Anche se non dovrebbe importare davvero. – adamw