自定义主键@TableGenerator重启后新值的问题

本文探讨了在使用Hibernate框架时遇到的一个关于主键生成的问题,即每次应用重启后生成的新ID总是比自定义表里的gen_val大allocationSize倍。通过深入分析源代码并调整配置参数,最终解决了这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=x-large][color=red][b]问题描述:[/b][/color][/size]
使用自定义表来构建主键,在每次重启之后的新id总是比定义表里面的gen_val大allocationSize倍。

Model的定义
@Entity
@TableGenerator(name = "rh_sys_portlet",
table = "rh_sys_tb_generator",
pkColumnName = "gen_name",
valueColumnName = "gen_value",
pkColumnValue = "rh_sys_portlet",
allocationSize = 5
)
@Table(name = "rh_sys_portlet")
public class RhSysPortlet extends BaseObject implements java.io.Serializable{
......
}



[size=x-large][color=red][b]问题原因:[/b][/color][/size]
org.hibernate.id.MultipleHiLoPerTableGenerator的configure()方法后面:
//hilo config
maxLo = ConfigurationHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
returnClass = type.getReturnedClass();

if ( maxLo >= 1 ) {
hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer( returnClass, maxLo );
}

当maxLo大于1的时候,就调用new OptimizerFactory.LegacyHiLoAlgorithmOptimizer( returnClass, maxLo ),
这个方法会调用到org.hibernate.id.enhanced.OptimizerFactory
public LegacyHiLoAlgorithmOptimizer(Class returnClass, int incrementSize) {
super( returnClass, incrementSize );
if ( incrementSize < 1 )
throw new HibernateException( "increment size cannot be less than 1" );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Creating hilo optimizer (legacy) with [incrementSize={0}; returnClass={1}]", incrementSize, returnClass.getName() );
}
maxLo = incrementSize;
lo = maxLo+1;
}

在这个代码运行之后就到:
@Override
public synchronized Serializable generate(AccessCallback callback) {
if ( lo > maxLo ) {
lastSourceValue = callback.getNextValue();
lo = lastSourceValue.eq( 0 ) ? 1 : 0;
hi = lastSourceValue.copy().multiplyBy( maxLo+1 );
}
value = hi.copy().add( lo++ );
return value.makeValue();
}

方法multiplyBy调用到org.hibernate.id.IdentifierGeneratorHelper
public IntegralDataTypeHolder multiplyBy(long factor) {
checkInitialized();
value *= factor;
return this;
}

=======================
在org.hibernate.id.MultipleHiLoPerTableGenerator
[color=red]maxLo = ConfigurationHelper.getInt(MAX_LO, params, Short.MAX_VALUE);可以看到,param里面的MAX_LO值,才出现这个问题。[/color]


[size=x-large][color=red][b]问题追溯:[/b][/color][/size]
那么继续找什么时候初始化这个param?
org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory
public IdentifierGenerator createIdentifierGenerator(String strategy, Type type, Properties config);


上面是被org.hibernate.mapping.SimpleValue
public IdentifierGenerator createIdentifierGenerator()
方法调用

在这个方法里面,identifierGeneratorProperties保存有max_lo信息,什么时候设定?
这个类里面有个
public void setIdentifierGeneratorProperties(Properties identifierGeneratorProperties) {
this.identifierGeneratorProperties = identifierGeneratorProperties;
}

被org.hibernate.cfg.BinderHelper类的
public static void makeIdGenerator()
调用

IdGenerator gen = mappings.getGenerator( generatorName, localGenerators );
gen里面设定params,然后传给这个方法的params。


最后参考文档:Hibernate Annotations参考文档 [url]http://www.okrs.cn/blog/news/?1027.html[/url], 知道注解加上
    @Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "rh_sys_portlet")
@GenericGenerator(name="rh_sys_portlet", strategy = "seqhilo",
parameters = {
@Parameter(name="max_lo", value = "1")
}
)
@Column(name = "portlet_id", unique = true, nullable = false)
public Long getPortletId() {
return this.portletId;
}

来设定这个max_lo值,就解决了问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值