2012-07-31 13 views
5

La entidad de hibernación que guardo en la base de datos (Oracle) tiene relaciones muy complejas, en el sentido de que tiene muchas entidades relacionadas. Se ve algo como esto ...StaleStateException al guardar entidad con relaciones complejas

@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. 

} 

también tengo un par de más entidades tales como ...

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

El truco es que tengo que hacer persistencia de Contract y entidades en TotalReturnSwap la misma transacción.

A veces podría ser un grupo de entidades que deben persistir en la misma transacción.

He notado la siguiente excepción cuando guardo la entidad TotalReturnSwap (que siempre se hace después de haber guardado la entidad 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) 

Ahora algunos puntos que pueden ayudar al responder preguntas:

  • Yo sólo estoy ahorrando (insertar) las entidades de base de datos - no actualizar/borrar/leyendo
  • he podido aislar esta excepción incluso en entornos de un solo subproceso, por lo que no parece un problema de subprocesos múltiples, aunque nuestra aplicación es multiproceso

Respuesta

17

El error puede ser causado por s everal cosas:

  1. Flushing los datos antes de cometer el objeto puede conducir a borrar todos los objetos pendiente para persistir.
  2. Si el objeto tiene clave principal que se genera automáticamente y está forzando una clave asignada
  3. si está limpiando el objeto antes de enviar el objeto a la base de datos.
  4. ID cero o incorrecto: si configura la ID en cero u otra cosa, Hibernate intentará actualizar en lugar de insertar.
  5. Objeto está a punto: Hibernate almacena en caché los objetos de la sesión. Si el objeto se modificó, e Hibernate no sabe de ello, lanzará esta excepción - en cuenta la StaleStateException

No estoy tomando el crédito por ello, lo encontró here.

+0

sobre # 5, ¿cómo podemos resolverlo? – Stony

+0

@Stony ¿Quizás un 'Refresh()'? – Michael

+0

@Michael Mi problema es que 2 hilos modifican el mismo pedido al mismo tiempo; entonces cuando guarde el PO, como el motivo # 5, haga una excepción. Entonces, ¿cuándo llamar a la actualización() en caso? Si antes de guardar(), el cambio para el PO simplemente se habrá ido. Finalmente, utilicé el bloqueo LockMode.PESSIMISTIC_WRITE para resolver mi problema. Alguien tiene una mejor solución? – Stony

0

Esto me sucedió en las siguientes circunstancias:

  • creé Objecta en código Java.
  • Agregué el objeto existenteB a objectA como un campo. objectB tiene una relación de uno a con objectA.
  • He guardado (creado) objectA en la base de datos.
  • Cuando se guardó objectA, objectB se actualizó en la base de datos para agregar id de objectA.

  • Luego agregué un objectC a objectA (un objectA para muchos objectCs ). Traté de actualizar objectA y obtuve la stalestateexception ... incluso cuando uso merge.

La respuesta es que necesitaba, ya sea de actualización objectB o recuperar una istance fresca de Objecta de la base de datos

Cuestiones relacionadas