Hibernate-Identifier generator

本文详细介绍了Hibernate中用于生成标识符的各种策略,包括IDENTITY、SEQUENCE、TABLE、AUTO等标准化的JPA生成器,以及额外的增强生成器如增量、UUID等。文章还讨论了HILO算法在不同场景下的应用,并提供了如何配置这些生成器的方法。

5.1.2.2. Identifier generator

Hibernate offers various generation strategies, let's explore the most common ones first that happens to be standardized by JPA:

  • IDENTITY: supports identity columns in DB2, MySQL, MS SQL Server, Sybase and HypersonicSQL. The returned identifier is of type longshort or int.

  • SEQUENCE (called seqhilo in Hibernate): uses a hi/lo algorithm to efficiently generate identifiers of type longshort or int, given a named database sequence.

  • TABLE (called MultipleHiLoPerTableGenerator in Hibernate) : uses a hi/lo algorithm to efficiently generate identifiers of type longshort or int, given a table and column as a source of hi values. The hi/lo algorithm generates identifiers that are unique only for a particular database.

  • AUTO: selects IDENTITYSEQUENCE or TABLE depending upon the capabilities of the underlying database.



Important

We recommend all new projects to use the new enhanced identifier generators. 

They are deactivated by default for entities using annotations but can be activated using hibernate.id.new_generator_mappings=true

These new generators are more efficient and closer to the JPA 2 specification semantic.

However they are not backward compatible with existing Hibernate based application (if a sequence or a table is used for id generation). 



@Entity
public class Customer {
   @Id @GeneratedValue
   Integer getId() { ... };
}

@Entity 
public class Invoice {
   @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
   Integer getId() { ... };
}

These are the four standard JPA generators. Hibernate goes beyond that and provide additional generators or additional options as we will see below. You can also write your own custom identifier generator by implementing org.hibernate.id.IdentifierGenerator.



The hbm.xml approach uses the optional <generator> child element inside <id>. If any parameters are required to configure or initialize the generator instance, they are passed using the <param> element.

<id name="id" type="long" column="cat_id">
        <generator class="org.hibernate.id.TableHiLoGenerator">
                <param name="table">uid_table</param>
                <param name="column">next_hi_value_column</param>
        </generator>
</id>


5.1.2.2.1. Various additional generators

All generators implement the interface org.hibernate.id.IdentifierGenerator. This is a very simple interface. Some applications can choose to provide their own specialized implementations, however, Hibernate provides a range of built-in implementations. The shortcut names for the built-in generators are as follows:

increment

generates identifiers of type longshort or int that are unique only when no other process is inserting data into the same table. Do not use in a cluster.

identity

supports identity columns in DB2, MySQL, MS SQL Server, Sybase and HypersonicSQL. The returned identifier is of type longshort or int.

sequence

uses a sequence in DB2, PostgreSQL, Oracle, SAP DB, McKoi or a generator in Interbase. The returned identifier is of type longshort or int

hilo

uses a hi/lo algorithm to efficiently generate identifiers of type longshort or int, given a table and column (by default hibernate_unique_key and next_hi respectively) as a source of hi values. The hi/lo algorithm generates identifiers that are unique only for a particular database.

seqhilo

uses a hi/lo algorithm to efficiently generate identifiers of type longshort or int, given a named database sequence.

uuid

Generates a 128-bit UUID based on a custom algorithm. The value generated is represented as a string of 32 hexidecimal digits. Users can also configure it to use a separator (config parameter "separator") which separates the hexidecimal digits into 8{sep}8{sep}4{sep}8{sep}4. Note specifically that this is different than the IETF RFC 4122 representation of 8-4-4-4-12. If you need RFC 4122 compliant UUIDs, consider using "uuid2" generator discussed below.

uuid2

Generates a IETF RFC 4122 compliant (variant 2) 128-bit UUID. The exact "version" (the RFC term) generated depends on the pluggable "generation strategy" used (see below). Capable of generating values as java.util.UUIDjava.lang.String or as a byte array of length 16 (byte[16]). The "generation strategy" is defined by the interface org.hibernate.id.UUIDGenerationStrategy. The generator defines 2 configuration parameters for defining which generation strategy to use:

uuid_gen_strategy_class

Names the UUIDGenerationStrategy class to use

uuid_gen_strategy

Names the UUIDGenerationStrategy instance to use

Out of the box, comes with the following strategies:

guid

uses a database-generated GUID string on MS SQL Server and MySQL.

native

selects identitysequence or hilo depending upon the capabilities of the underlying database.

assigned

lets the application assign an identifier to the object before save() is called. This is the default strategy if no <generator> element is specified.

select

retrieves a primary key, assigned by a database trigger, by selecting the row by some unique key and retrieving the primary key value.

foreign

uses the identifier of another associated object. It is usually used in conjunction with a <one-to-one>primary key association.

sequence-identity

a specialized sequence generation strategy that utilizes a database sequence for the actual value generation, but combines this with JDBC3 getGeneratedKeys to return the generated identifier value as part of the insert statement execution. This strategy is only supported on Oracle 10g drivers targeted for JDK 1.4. Comments on these insert statements are disabled due to a bug in the Oracle drivers.



5.1.2.2.2. Hi/lo algorithm
....













<think>好的,我现在需要解决用户提到的Hibernate中的AssertionFailure异常,特别是与null标识符相关的错误。首先,我需要回忆一下Hibernate的相关知识,特别是关于标识符(identifier)的部分。AssertionFailure通常表明Hibernate在内部状态检查时失败,可能的原因包括标识符为null、实体映射不正确或者事务管理问题。 用户提到的是null标识符异常,所以可能的情况是当Hibernate尝试将一个实体保存或加载到会话中时,发现该实体的主键(identifier)为null。根据Hibernate的要求,实体类的主键字段必须是非空的,尤其是在使用数据库自增主键或手动分配时,如果没有正确生成或赋值,就会导致这个问题。 首先,我应该检查实体类的映射配置是否正确。例如,使用@Id注解标识主键字段,并确保生成策略(如@GeneratedValue)正确设置。如果使用自增主键,策略应该是GenerationType.IDENTITY,而如果是序列或表生成,需要相应配置。如果生成策略配置错误,可能导致Hibernate期望数据库或程序生成主键,但实际上没有生成,导致保存时主键仍为null。 接下来,考虑在保存实体之前是否手动设置了主键。如果生成策略是手动分配(如GenerationType.NONE),则需要在保存前主动赋值。否则,Hibernate应该在插入数据库时自动生成主键值,但如果数据库没有正确返回生成的值(例如,触发器或存储过程未正确配置),也可能导致问题。 另外,事务管理的问题也可能引发此类异常。例如,在事务未正确提交或回滚的情况下,Hibernate可能无法正确同步实体状态,导致标识符未正确填充。需要确保事务边界正确,并且在保存实体后及时提交事务。 还有可能是在级联操作或关联关系中,某个关联实体的标识符未被正确设置。例如,父实体保存时,子实体的主键需要依赖父实体的主键生成,如果级联配置不当,可能导致子实体的主键为null。 此外,Hibernate的会话管理也需要检查。如果会话(Session)在操作过程中被意外关闭或未正确绑定到当前线程,可能导致实体状态不一致。例如,用户引用的代码中的bindHibernateSessionToThread方法,可能是用来将会话绑定到线程的,如果该方法未被正确调用或配置,可能导致会话问题,进而影响主键的生成和持久化。 还需要考虑数据库的约束,例如主键是否为自增字段,是否允许null值。如果数据库表的主键字段设置为非自增且不允许null,但Hibernate配置为自动生成,可能导致冲突。 总结可能的解决步骤: 1. 检查实体类的主键映射,确保@Id和@GeneratedValue正确配置,生成策略符合数据库设计。 2. 确保在保存实体之前没有手动设置主键,或根据生成策略正确赋值。 3. 验证事务管理配置,确保保存操作在事务内完成,并正确提交。 4. 检查关联实体和级联配置,确保关联对象的主键正确生成。 5. 确保Hibernate会话管理正确,特别是在多线程环境下会话绑定到当前线程。 6. 检查数据库表结构,确认主键字段的约束与Hibernate配置一致。 用户提供的引用中提到了Hibernate 4.1.9的BatchedTooManyRowsAffectedException,这可能与批量更新操作有关,但当前问题更偏向于标识符为null的情况。不过,可能需要检查是否存在批量操作中的错误影响了主键的生成,例如批量插入时未正确处理生成的主键值。 最后,根据这些分析,给出具体的解决步骤和建议,帮助用户逐步排查问题,并确保配置和代码的正确性。</think>### 解决Hibernate中`AssertionFailure: null identifier`异常的方法 `org.hibernate.AssertionFailure: null identifier`异常通常发生在Hibernate尝试操作一个实体对象时,发现其主键(identifier)为`null`。以下是逐步排查和解决的方案: --- #### **1. 检查实体类的主键映射配置** - **原因**:实体类的主键未正确配置生成策略,或数据库未返回生成的主键值。 - **解决方案**: - 确保主键字段使用`@Id`和`@GeneratedValue`注解,并根据数据库类型选择合适的生成策略: ```java @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 适用于自增主键(如MySQL) private Long id; ``` - 若使用序列(如Oracle),需指定`GenerationType.SEQUENCE`并配置序列名称: ```java @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_gen") @SequenceGenerator(name = "seq_gen", sequenceName = "my_sequence") ``` --- #### **2. 验证主键生成策略与数据库的一致性** - **原因**:数据库表的主键生成方式(如自增、序列)与Hibernate配置不匹配。 - **解决方案**: - 检查数据库表结构,确认主键是否为自增字段或依赖序列生成。 - 若使用`GenerationType.IDENTITY`,确保数据库支持自增(如MySQL的`AUTO_INCREMENT`或PostgreSQL的`SERIAL`)。 --- #### **3. 避免手动设置主键值** - **原因**:如果主键生成策略为自动生成(如`GenerationType.IDENTITY`),手动赋值会导致冲突。 - **解决方案**: - 移除手动设置主键的代码: ```java // 错误示例:手动设置自增主键 entity.setId(123L); session.save(entity); ``` --- #### **4. 检查事务管理与会话绑定** - **原因**:事务未正确提交或会话未绑定到当前线程,导致主键未持久化。 - **解决方案**: - 确保操作在事务内执行,并使用`@Transactional`注解(Spring环境): ```java @Transactional public void saveEntity(MyEntity entity) { sessionFactory.getCurrentSession().save(entity); } ``` - 验证会话绑定逻辑,如使用`bindHibernateSessionToThread`确保会话与线程绑定[^1]。 --- #### **5. 排查关联实体的级联操作** - **原因**:级联保存时,关联实体的主键可能未正确生成。 - **解决方案**: - 检查关联关系的`cascade`配置,确保包含`CascadeType.PERSIST`或`CascadeType.ALL`: ```java @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private List<ChildEntity> children; ``` --- #### **6. 检查数据库连接和约束** - **原因**:数据库连接异常或主键约束冲突。 - **解决方案**: - 确认数据库连接正常,表结构主键字段非空且无重复值。 - 启用Hibernate的SQL日志,检查生成的INSERT语句是否包含主键: ```properties hibernate.show_sql=true hibernate.format_sql=true ``` --- #### **示例代码修正** ```java // 正确的实体类配置示例 @Entity public class MyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 其他字段及Getter/Setter } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值