2012-07-31 10 views
5

L'entità di ibernazione che sto salvando nel database (Oracle) ha relazioni molto complesse, nel senso che ha molte entità correlate. Sembra qualcosa di simile ...StaleStateException durante il salvataggio di entità con relazioni complesse

@Table(name = "t_HOP_CommonContract") 
public class Contract { 
    @Id 
    private ContractPK id; 

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    private ContractGroupMember contractGroupMember; 

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    @JoinColumns({ 
     @JoinColumn(name = "TransactionId", referencedColumnName = "TransactionId"), 
     @JoinColumn(name = "PrimaryContractId", referencedColumnName = "PrimaryContractId") 
    }) 
    @Fetch(FetchMode.SUBSELECT) 
    private List<ContractLink> contractLinks; 

    // . . . . . . . 

    // A couple of more one to many relationships 

    // Entity getters etc. 

} 

Ho anche un altro paio di entità come ...

@Table(name = "t_HOP_TRS") 
public class TotalReturnSwap { 
    @Id 
    private ContractPK id; 
    // Entity Getters etc. 
} 

Il trucco è che devo fare la persistenza di Contract e TotalReturnSwap entità la stessa transazione.

A volte potrebbe essere un gruppo di entità che devono essere mantenute nella stessa transazione.

Ho notato la seguente eccezione quando salvo l'entità TotalReturnSwap (che viene sempre eseguita dopo aver salvato l'entità Contract).

org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is 
    org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:675) \ 
    at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793) 
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) 
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147) 
    at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.performTDWPersistenceForContracts(DownstreamContractBusinessEventPostingService.java:102) 
    at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.persistContractBusinessEvent(DownstreamContractBusinessEventPostingService.java:87) 
    at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.publish(DownstreamContractBusinessEventPostingService.java:67) 
    at com.rbs.fcg.publishing.PublishingProcessor.publish(PublishingProcessor.java:76) 
    at com.rbs.fcg.publishing.PublishingProcessor.process(PublishingProcessor.java:52) 
    at com.rbs.are.MultiThreadedQueueItemProcessor$2.run(MultiThreadedQueueItemProcessor.java:106) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85) 
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70) 

Ora un paio di punti che possono aiutare, mentre rispondendo alle domande:

  • sto solo salvando (inserimento) entità in database - mai l'aggiornamento/cancellazione/leggendo
  • sono stato in grado di isolare questa eccezione anche in ambienti a thread singolo, quindi non sembra un problema di multi-threading, anche se la nostra applicazione è multi-thread

risposta

17

L'errore può essere causato da s everal things:

  1. Il lavaggio dei dati prima di commettere l'oggetto può comportare la cancellazione di tutti gli oggetti in sospeso per la persistenza.
  2. Se l'oggetto ha una chiave primaria generata automaticamente e si sta forzando una chiave assegnata
  3. se si sta pulendo l'oggetto prima di commettere l'oggetto nel database.
  4. ID zero o errato: se si imposta l'ID su zero o qualcos'altro, Hibernate proverà ad aggiornare anziché inserire.
  5. L'oggetto è obsoleto: Hibernate memorizza nella cache gli oggetti della sessione. Se l'oggetto è stato modificato, e Hibernate non sa a questo proposito, si getterà questa eccezione - nota lo StaleStateException

non sto prendendo il merito per questo, ho trovato here.

+0

A proposito di # 5, come possiamo risolverlo? – Stony

+0

@Stony Forse un 'Refresh()'? – Michael

+0

@Michael Il mio problema è che 2 thread modificano lo stesso PO allo stesso tempo; quindi, quando salva il PO, come motivo # 5, lancia un'eccezione. quindi quando chiami l'aggiornamento() nel caso? Se before save(), la modifica per l'ordine PO sarà scomparsa. Infine, ho usato il lock LockMode.PESSIMISTIC_WRITE per risolvere il mio problema. Qualcuno ha una soluzione migliore? – Stony

0

Questo è accaduto a me nelle seguenti circostanze:

  • ho creato Objecta nel codice Java.
  • Ho aggiunto l'oggetto esistenteB all'oggettoA come campo. objectB ha uno a una relazione con objectA.
  • Ho salvato (creato) oggettoA nel database.
  • Quando oggettoA è stato salvato, oggettoB è stato aggiornato nel database per aggiungere l'ID dell'oggettoA.

  • Quindi ho aggiunto un oggettoC all'oggettoA (un oggettoA per molti oggettiC). Ho provato ad aggiornare objectA e ho ottenuto l' stalestateexception .... anche quando si usa l'unione.

la risposta è che avevo bisogno di uno aggiornamento ObjectB o recuperare un'istanza fresca Objecta dal database