2008-09-17 98 views
10

是否有一個解決方案批量插入通過hibernate在分區postgresql表?目前我得到這樣的錯誤...休眠插入與分區postgresql批處理

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

我發現這個鏈接http://lists.jboss.org/pipermail/hibernate-dev/2007-October/002771.html但我不能隨時隨地在網絡上找到的這個問題很好解決,或者它如何能得到解決

+0

任何其他對Hibernate 3.5的解決方案? – 2010-05-25 13:58:16

回答

4

您可能想要通過設置hibernate.jdbc.factory_class屬性嘗試使用自定義的Batcher。確保hibernate不會檢查批處理操作的更新計數可能會解決您的問題,您可以通過使您的自定義Batcher擴展BatchingBatcher類,然後覆蓋doExecuteBatch(...)方法來實現這一目標:

@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; 
      } 

     } 

    } 

請注意,新方法不檢查執行預準備語句的結果。請記住,做出這種改變可能會以某種意想不到的方式影響休眠(或者可能不會)。

2

thnx!它的伎倆,沒有問題POP操作起來,到目前爲止:)......有一件事你... 我不得不實施BatcherFactory類,並把它詮釋了persistence.xml文件, 這樣的:

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

從工廠我已經打電話給我的代碼實現批量化上面

PS 休眠核心3.2.6 GA

再次感謝

+0

通過忽略批處理計數是否可以解決您的問題,還是忽略錯誤? 我有同樣的錯誤,我不知道爲什麼它的發生或意味着什麼,如果我嘗試重寫分批跳過它? – Dougnukem 2009-06-04 23:56:19

+1

這是如何與Hibernate 3.2.6 GA一起工作的BatchingBatcher實現將batchSize作爲私有字段,因此擴展它我無法訪問它。 – Dougnukem 2009-06-05 00:02:02

1

出現,如果你可以使用規則的INSTEAD OF觸發器用於插入,那麼它可以返回正確的數字,而只用沒有WHERE語句的單個RULE。

ref1

ref2

ref3

另一種選擇可能是創建一個「包裝」的分區表,那麼你就返回新排出來,以指示成功行更新視圖,而不不小心將額外的不需要的行添加到主表中。

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 

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

如果你去視圖包裝路線的一個選項是還定義微不足道「而不是」觸發器刪除和更新,以及,那麼你可以使用的名稱查看錶以代替所有交易中的普通表。

使用該視圖的另一個選擇是創建插入規則,以便主表上的任何插入都轉到視圖[使用其觸發器],前(假設您已經創建了partitioned_insert_trigger和tablename_view和insert_view_trigger,如上所列)

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

然後它會使用你的新的工作視圖包裝插入。

0

我面臨同樣的問題,同時通過Hibernate插入文件後,很多搜索發現,它期待的是更新的行應如此,而不是它空變化的觸發程序新的,這將解決問題的返回如下圖所示

RETURN新