采用GenerationType.TABLE策略时,如何获取下一个ID并让JPA跳过它?
解决TABLE策略自定义序列表获取下一个ID并确保后续对象跳过该ID的方法
当使用Hibernate的enhanced-table策略搭配pooled-lo优化器(增量大小>1)时,直接操作数据库序列表会导致内存中的ID池与数据库不同步,进而引发ID冲突。正确的做法是通过Hibernate原生API获取ID,这样既能拿到下一个可用ID,又能保证后续创建实体时自动跳过该ID,复用内存中的ID池。
具体实现步骤
- 获取Hibernate Session:从JPA的
EntityManager中解包得到Hibernate的Session实例。 - 获取对应的标识符生成器:通过SessionFactory拿到你定义的
TestIdGenerator实例。 - 生成下一个ID:调用生成器的
generate方法,传入Session和实体实例,获取的ID会从当前内存ID池中取出,后续创建实体时自动使用池中的下一个ID。
代码示例
// 1. 获取EntityManager(根据你的环境,比如Spring注入或手动获取) @Autowired private EntityManager entityManager; public Integer getNextTestId() { // 2. 解包得到Hibernate Session Session session = entityManager.unwrap(Session.class); // 3. 获取自定义的标识符生成器 IdentifierGenerator generator = session.getSessionFactory() .getIdentifierGenerator("TestIdGenerator"); // 4. 生成下一个ID(传入空的实体实例即可) TestEntity emptyTest = new TestEntity(); return (Integer) generator.generate(session, emptyTest); }
关键说明
- 该方法会严格遵循
pooled-lo优化器的逻辑:如果当前内存ID池还有剩余,直接返回池中的下一个ID;如果池已耗尽,会自动向数据库申请下一批(20个)ID,更新序列表后返回第一个。 - 禁止直接修改数据库的
sequences表:手动修改会导致Hibernate内存池中的ID与数据库不一致,后续创建实体时极大概率出现ID重复或主键冲突。 - 生成的ID可以直接用于其他业务操作,后续通过JPA创建
TestEntity实例时,Hibernate会自动使用ID池中的下一个可用ID,不会重复使用你已获取的这个ID。
内容的提问来源于stack exchange,提问作者Dzhenko
相关产品推荐
相关产品推荐

