緩存問題是因爲Hibernate默認爲一個Oracle方言做兩件事情。它爲所有主鍵生成的表格創建一個序列共享序列,並且序列緩存每次20個數字,如果它們沒有在特定的時間範圍內使用,則Oracle將放棄其餘部分。
下面的Oracle解決方案來自Burt Beckwith的一篇文章,其中有一段tweek用於防止Oracle序列緩存數字。因此,這種方言會爲你做兩件事:
- 它會爲每個表創建一個單一的序列,所以序列不共享,主鍵號不會跨表分割。
- 它將禁用Oracle中的數字緩存,因此您不會在過期的緩存中丟失任何序列號。這是使用
NOCACHE
命令在PARAMETERS
屬性中設置的。
既然你是在你很可能帶出每個表的邏輯順序,並在NOCACHE
序列定義以達到您想要的結果離開映射定義你的表的順序。
此外,您需要從現有表空間中刪除序列,因爲Grails不會重新創建它,除非在create
和create-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
這應該很好。我認爲Hibernate總是會調用MY_SEQ.NEXTVAL,而不管序列是否被緩存;緩存在Oracle內部發生,而不是在Hibernate或JDBC級別。 請注意,如果您的應用程序依賴於沒有數字序列中的空白,那麼使用Oracle序列可能不是正確的方法。不能保證你在序列中沒有任何差距 - 你可能有不同的線程獲取序列值,或者你可能有回滾。 –