2008-09-17 4 views
10

Y a-t-il une solution pour l'insertion par lots via hibernate dans une table postgresql partitionnée? actuellement je reçois une erreur comme ça ...hibernate insert batch avec postgresql partitionné

ERROR org.hibernate.jdbc.AbstractBatcher - Exception executing batch: 
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:61) 
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46) 
    at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68).... 

j'ai trouvé ce lien http://lists.jboss.org/pipermail/hibernate-dev/2007-October/002771.html mais je ne trouve nulle part sur le web est ce problème résolu ou comment il peut être obtenir autour

+0

D'autres solutions pour Hibernate 3.5? –

Répondre

4

Vous pouvez essayer d'utiliser un Batcher personnalisé en définissant la propriété hibernate.jdbc.factory_class. S'assurer qu'hibernate ne vérifie pas le nombre de mises à jour des opérations par lots pourrait résoudre votre problème, vous pouvez y parvenir en rendant votre Batcher personnalisé étendre la classe BatchingBatcher, puis en remplaçant la méthode doExecuteBatch (...) par:

@Override 
    protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { 
     if (batchSize == 0) { 
      log.debug("no batched statements to execute"); 
     } 
     else { 
      if (log.isDebugEnabled()) { 
       log.debug("Executing batch size: " + batchSize); 
      } 

      try { 
//    checkRowCounts(ps.executeBatch(), ps); 
       ps.executeBatch(); 
      } 
      catch (RuntimeException re) { 
       log.error("Exception executing batch: ", re); 
       throw re; 
      } 
      finally { 
       batchSize = 0; 
      } 

     } 

    } 

Notez que la nouvelle méthode ne vérifie pas les résultats de l'exécution des instructions préparées. Gardez à l'esprit que cette modification peut affecter Hibernate d'une manière inattendue (ou peut-être pas).

2

thnx! il a fait l'affaire, aucun problème poped, jusqu'à ce jour:) .... une chose que tu ... je devais mettre en œuvre la classe BatcherFactory et le mettre int le fichier persistence.xml, comme ceci:

property name="hibernate.jdbc.factory_class" value="path.to.my.batcher.factory.implementation" 

de cette usine, je l'ai appelé ma mise en œuvre de Doseur avec le code ci-dessus

ps mise en veille prolongée noyau 3.2.6 GA

Merci encore une fois

+0

En ignorant le nombre de lots, cela résout-il votre problème ou ignore-t-il simplement l'erreur? Je suis la même erreur et je ne peux pas dire pourquoi cela se passe ou ce que cela signifie si je tente de remplacer le Batcher pour l'ignorer? – Dougnukem

+1

Comment cela fonctionne-t-il avec Hibernate 3.2.6 GA L'implémentation de BatchingBatcher a batchSize comme un champ privé, donc je n'ai pas accès à ce champ. – Dougnukem

+1

il ignore le problème, mais toutes les valeurs sont dans la base de données, donc il fait l'affaire pour moi ... j'ai étendu la classe AbstractBatcher – tropikalista

1

Apparaît si vous pouvez utiliser des règles au lieu de déclencheurs pour l'insertion, il peut renvoyer le bon numéro, mais seulement avec une seule règle sans une instruction WHERE.

ref1

ref2

ref3

une autre option peut être de créer une vue que « wraps » La table partitionnée, puis vous revenez la ligne NOUVEAU sur pour indiquer une mise à jour de la ligne réussie, sans ajouter accidentellement une ligne indésirable supplémentaire à la table principale.

create view tablename_view as select * from tablename; -- create trivial wrapping view 

CREATE OR REPLACE FUNCTION partitioned_insert_trigger() -- partitioned insert trigger 
RETURNS TRIGGER AS $$ 
BEGIN 
    IF (NEW.partition_key>= 5500000000 AND 
     NEW.partition_key < 6000000000) THEN 
     INSERT INTO tablename_55_59 VALUES (NEW.*); 
    ELSIF (NEW.partition_key >= 5000000000 AND 
      NEW.partition_key < 5500000000) THEN 
     INSERT INTO tablename_50_54 VALUES (NEW.*); 
    ELSIF (NEW.partition_key >= 500000000 AND 
      NEW.partition_key < 1000000000) THEN 
     INSERT INTO tablename_5_9 VALUES (NEW.*); 
    ELSIF (NEW.partition_key >= 0 AND 
      NEW.partition_key < 500000000) THEN 
     INSERT INTO tablename_0_4 VALUES (NEW.*); 
    ELSE 
     RAISE EXCEPTION 'partition key is out of range. Fix the trigger function'; 
    END IF; 
    RETURN NEW; -- RETURN NEW in this case, typically you'd return NULL from this trigger, but for views we return NEW 
END; 
$$ 
LANGUAGE plpgsql; 

CREATE TRIGGER insert_view_trigger 
    INSTEAD OF INSERT ON tablename_view 
    FOR EACH ROW EXECUTE PROCEDURE partitioned_insert_trigger(); -- create "INSTEAD OF" trigger 

ref: http://www.postgresql.org/docs/9.2/static/trigger-definition.html

Si vous êtes allé la route wrapper vue d'une option est de définir aussi trivial « au lieu de » déclenche pour supprimer et mettre à jour, ainsi, vous pouvez simplement utiliser le nom du Voir la table à la place de votre table normale dans toutes les transactions.Une autre option qui utilise la vue est de créer une règle d'insertion pour que les insertions de la table principale accèdent à la vue [qui utilise son déclencheur], ex (en supposant que vous avez déjà partitioned_insert_trigger et que tablename_view et insert_view_trigger sont créés comme indiqué ci-dessus

create RULE use_right_inserter_tablename AS 
     ON INSERT TO tablename 
     DO INSTEAD insert into tablename_view VALUES (NEW.*); 

Ensuite, il utilisera votre nouvel insert d'encapsulation de vue de travail.

0

J'ai fait face au même problème lors de l'insertion des documents par mise en veille prolongée après beaucoup de recherche a trouvé qu'il attend que les lignes mises à jour doivent être retournées donc au lieu de changement nul à nouveau dans la procédure de déclenchement qui résoudra le problème comme indiqué ci-dessous

RETOUR NOUVEAU