我意识到这比Grails更像是一个休眠问题。在负载平衡(2节点)环境中,我看到我的对象的id跳了很多。即使没有重新启动应用服务器,我也看到数字有时会跳过10个数字。我怀疑hibernate会话正在缓存一个序列值块。 有没有办法用grails 1.3.7来控制这种行为?基本上我没关系服务器每次需要时从数据库中提取nextval。
我的域对象序列声明(对于2个对象相同):
static mapping = {
id generator:'sequence', params:[sequence:'MY_SEQ']
}
答案 0 :(得分:3)
缓存问题是因为Hibernate默认使用Oracle方言,它执行两项操作。它创建了一个在所有表中共享的序列,用于生成主键,序列一次缓存20个数字,如果它们未在特定时间范围内使用,Oracle将丢弃其余的数据。
以下Oracle解决方案来自Burt Beckwith的帖子,其中包含一个防止Oracle序列缓存数字的内容。因此,这种方言会为你做两件事:
PARAMETERS
命令在NOCACHE
属性中设置的。由于您在映射中定义了表的序列,因此可能会删除每个表逻辑的序列,并保留NOCACHE
序列定义以获得所需的结果。
此外,您需要从现有表空间中删除序列,因为Grails不会重新创建它,但create
和create-drop
方案除外。执行此操作时,您可能还希望提高新序列的起始值,以防止数据库已使用的密钥发生主键问题冲突。
使用方言将dialect = SequencePerTableOracleDialect
添加到dataSource定义闭包中的DataSource.groovy
文件中。
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;
}
}
}
此链接在此问题上有一些历史记录,包含Burt原始代码的链接以及PostGreSql的响应:Hibernate & postgreSQL with Grails
答案 1 :(得分:3)
我已经进入数据库并使用以下DDL修改了序列:
ALTER SEQUENCE MY_SEQ NOCACHE;
我认为这是此问题的最佳解决方案。有没有人看到这种方法的潜在问题?
全部谢谢!