缓存问题是因为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序列可能不是正确的方法。不能保证你在序列中没有任何差距 - 你可能有不同的线程获取序列值,或者你可能有回滚。 –