2011-11-30 38 views
5

我意識到這是一個比Grails更多的休眠問題。在一個負載均衡(2個節點)的環境中,我看到我的對象的ID正在跳轉很多。即使沒有重新啓動應用程序服務器,我也會看到數字跳過10,有時候是20個數字。我懷疑休眠會話正在緩存一個序列值塊。 有沒有辦法用grails 1.3.7來控制這種行爲?本質上,我確定服務器每次需要時都從數據庫中拉取nextval。針對Oracle 11g的Grails序列生成

我的域對象序列聲明(同爲2個對象):

static mapping = { 
     id generator:'sequence', params:[sequence:'MY_SEQ'] 
    } 

回答

3

因爲我已經去到數據庫並修改與以下DDL序列:

ALTER SEQUENCE MY_SEQ NOCACHE; 

我認爲這是解決此問題的最佳解決方案。有沒有人看到這種方法的潛在問題?

謝謝大家!

+1

這應該很好。我認爲Hibernate總是會調用MY_SEQ.NEXTVAL,而不管序列是否被緩存;緩存在Oracle內部發生,而不是在Hibernate或JDBC級別。 請注意,如果您的應用程序依賴於沒有數字序列中的空白,那麼使用Oracle序列可能不是正確的方法。不能保證你在序列中沒有任何差距 - 你可能有不同的線程獲取序列值,或者你可能有回滾。 –

3

緩存問題是因爲Hibernate默認爲一個Oracle方言做兩件事情。它爲所有主鍵生成的表格創建一個序列共享序列,並且序列緩存每次20個數字,如果它們沒有在特定的時間範圍內使用,則Oracle將放棄其餘部分。

下面的Oracle解決方案來自Burt Beckwith的一篇文章,其中有一段tweek用於防止Oracle序列緩存數字。因此,這種方言會爲你做兩件事:

  • 它會爲每個表創建一個單一的序列,所以序列不共享,主鍵號不會跨表分割。
  • 它將禁用Oracle中的數字緩存,因此您不會在過期的緩存中丟失任何序列號。這是使用NOCACHE命令在PARAMETERS屬性中設置的。

既然你是在你很可能帶出每個表的邏輯順序,並在NOCACHE序列定義以達到您想要的結果離開映射定義你的表的順序。

此外,您需要從現有表空間中刪除序列,因爲Grails不會重新創建它,除非在createcreate-drop方案中。當你這樣做的時候,你也可能想要提高新序列的起始值,以防止數據庫已經使用的密鑰與主密鑰相沖突。

要使用dialect將dialect = SequencePerTableOracleDialect添加到您的DataSource.groovy文件的dataSource定義閉包中。

import java.util.Properties; 

import org.hibernate.dialect.Dialect; 
import org.hibernate.dialect.Oracle10gDialect; 
import org.hibernate.id.PersistentIdentifierGenerator; 
import org.hibernate.id.SequenceGenerator; 
import org.hibernate.type.Type; 

public class SequencePerTableOracleDialect extends Oracle10gDialect { 
    public static final String PARAMETERS = "MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE NOCYCLE"; 

    /** 
    * Get the native identifier generator class. 
    * 
    * @return TableNameSequenceGenerator. 
    */ 
    @Override 
    public Class<?> getNativeIdentifierGeneratorClass() { 
     return TableNameSequenceGenerator.class; 
    } 

    /** 
    * Creates a sequence per table instead of the default behavior of one 
    * sequence. 
    */ 
    public static class TableNameSequenceGenerator extends SequenceGenerator { 

     /** 
     * {@inheritDoc} If the parameters do not contain a 
     * {@link SequenceGenerator#SEQUENCE} name, we assign one based on the 
     * table name. 
     */ 
     @Override 
     public void configure(final Type type, final Properties params, 
       final Dialect dialect) { 
      if (params.getProperty(SEQUENCE) == null 
        || params.getProperty(SEQUENCE).length() == 0) { 
       /* Sequence per table */ 
       String tableName = params 
         .getProperty(PersistentIdentifierGenerator.TABLE); 
       if (tableName != null) { 
        params.setProperty(SEQUENCE, createSequenceName(tableName)); 
       } 
       /* Non-Caching Sequence */ 
       params.setProperty(PARAMETERS, SequencePerTableOracleDialect.PARAMETERS); 
      } 
      super.configure(type, params, dialect); 
     } 

     /** 
     * Construct a sequence name from a table name. 
     * 
     * @param tableName 
     *   the table name 
     * @return the sequence name 
     */ 
     String createSequenceName(final String tableName) { 
      return "seq_" + tableName; 
     } 
    } 
} 

此鏈接對這個問題的一些歷史,並鏈接到伯特的原代碼,並且對於PostgreSQL的響應:Hibernate & postgreSQL with Grails

+0

謝謝!你是否說沒有辦法在params中爲序列指定NOCACHE或allocationSize? – dbrin

+0

據我所知,不會,因爲這將是數據庫特定的SQL,它會將您的應用程序綁定到特定品牌的數據庫。 – schmolly159

+0

對不起。這不是我正在尋找的解決方案。我會將其標記爲對其他人有用。查看我的解決方案以獲得其他簡單修復...至少我認爲是這樣:) – dbrin