存储在数据库中的每个实体对象都有一个主键。
作为对象数据库,ObjectDB支持隐式对象ID,因此不需要显式定义的主键。但ObjectDB还支持显式的标准JPA主键,包括复合主键和自动序列值生成。这是ObjectDB的一个非常强大的特性,它在其他面向对象的数据库中是不存在的。
本页包含以下主题:
实体标识
自动主键
应用程序集主键
复合主键
嵌入的主键
获取主键
使用主键进行对象聚类
数据库中的每个实体对象都通过其类型和主键的组合进行唯一标识(并且可以从数据库中检索)。每个实体类的主键值都是唯一的。但是,不同实体类的实例可以共享相同的主键值。
只有实体对象有主键。其他可持久类型的实例始终存储为包含其的实体对象的一部分,并且没有自己的独立标识。
默认情况下,主键是一个连续的64位数字(long),由objectdb为数据库中存储的每个新实体对象自动设置。数据库中第一个实体对象的主键为1,第二个实体对象的主键为2等。从数据库中删除实体对象时,不会回收主键值。
可以通过声明主键字段来访问实体的主键值:
@Entity
public class {
@Id @Generated long id; //自动生成
}
@id注释将字段标记为主键字段。定义主键字段时,ObjectDB会自动将主键值注入该字段。
@generatedvalue注释指定由objectdb自动分配主键。自动值生成在“生成的值”部分中进行了详细讨论。
如果实体的主键字段未标记为@GeneratedValue,则不会生成自动主键值,应用程序负责通过初始化主键字段来设置主键。在尝试持久化实体对象之前必须执行此操作。
由应用程序设置的主键字段可以是以下类型之一:
当一个实体有多个主键字段时,JPA规范要求用户必须自定义一个特殊的ID类,规范如下:
//主键类
Class ProjectId {
int departmentId;
long projectId;
...
}
//Entity类
@Entity @IdClass(ProjectId.class)
public class Project {
@Id int departmentId;
@Id long projectId;
...
}
ObjectDB不强制定义ID类。但是,如果实体对象必须由其主键检索,则需要ID类。
表示复合主键的另一种方法是使用可嵌入类,自定义一个可嵌入类需要对类做@Embeddable标注。然后在Entity类中定义一个此可嵌入类型的字段作为主键,并对此字段加@EmbeddedId标注
@Entity
public class Project {
@EmbeddedId ProjectId id;
...
}
@Embeddable
Class ProjectId {
int departmentId;
long projectId;
}
JPA2提供了一种获取指定托管实体对象的对象ID(主键)的通用方法。例如:
persistenceUnitUtil=emf.getPersistenceUnitUtil();//从EntityManagerFactory获取PersistenceUnitUtil实例。
projectID=util.getIdentifier(project);
getIdentifier方法接受一个参数,一个托管实体对象,并返回主键。对于复合主键-返回ID类或可嵌入类的实例。
实体对象物理存储在数据库中,并按主键排序。有时,选择一个主键可以帮助以有效的方式对数据库中的实体对象进行集群。这在使用返回大型结果集的查询时特别有用。
例如,考虑一个实时系统,它检测来自不同传感器的事件并将详细信息存储在数据库中。每个事件都由一个事件实体对象表示,该对象包含时间、传感器ID和其他详细信息。假设检索指定时间段内指定传感器的所有事件的查询是常见的,并返回数千个事件对象。在这种情况下,以下主键可以显著提高查询运行性能:
@Entity
public class Event {
@EmbeddedId EventId id;
:
}
@Embeddable
Class EventId {
int sensorId;
Date time;
}
由于实体对象是按其主键在数据库中排序的,所以同一传感器在一段时间内的事件是连续存储的,可以通过访问最少数量的数据库页来收集。
另一方面,这样的主键需要更多的存储空间(尤其是当数据库中有许多对事件对象的引用时,因为对实体的引用包含主键值),并且在存储操作中效率较低。因此,必须考虑所有因素,可能需要一个基准来评估不同的备选方案,以便选择最佳解决方案。