默认情况下,Hibernate创建一个globel序列,用于为所有表生成id(在PostgreSQL的情况下),它可以扩展非常糟糕的恕我直言。虽然我可以为每个实体类型指定使用哪个序列,但我不喜欢这样做。我不喜欢明确命名序列和强制使用序列作为生成器策略,因为我希望hibernate为可能根本不支持序列的数据库生成DDL。单个全局序列也使得无法使用32位int作为主键,这意味着我必须将所有int id转换为long类型。
答案 0 :(得分:4)
Hibernate意味着是独立于数据库的ORM解决方案,但在迁移到另一个数据库供应商时会遇到一些关键问题。其中之一是底层数据库的自动ID生成。 MySQL,Oracle& MS SQL Server都使用不同的技术来为主键生成自动ID。因此,当我们开始迁移时,我们面临很多问题,额外的工作应该不是这样。
之前的Hibernate 3.2.3 Hibernate没有适当的解决方案,但在3.2.3版本中,Hibernate的人们可以提供这样的便携式ID生成器,它可以在任何数据库上运行良好。这两个是以下,
“可移植性所采用的方法是,你真的不在乎你是否在数据库中使用SEQUENCE;你真的只想要一个类似序列的值生成。在支持SEQUENCES的数据库上,SequenceStyleGenerator实际上将使用SEQUNCE作为值生成器;对于那些不支持SEQUENCES的数据库,它将使用单行表作为值生成器,但具有与SEQUENCE值生成器相同的精确特征(即它始终处理单独事务中的序列表) ”
虽然没有专门针对可移植性,但TableGenerator当然可以在所有数据库中使用。它使用多行表,其中行由(可配置的)sequence_name列键入;一种方法是让每个实体在表中定义唯一的sequence_name值以分割其标识符值。它来自较旧的org.hibernate.id.MultipleHiLoPerTableGenerator,并使用基本相同的表结构。但是,虽然MultipleHiLoPerTableGenerator固有地将hi-lo算法应用于值生成,但添加了这个新的TableGenerator以便能够利用可插入的优化器。
示例实体在所有数据库中使用Hibernate的序列。
@Entity
@Table(name = "author")
public class Author implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Date birthDate;
private Date deathDate;
private String bio;
private String wikiUrl;
private String imagePath;
private Boolean isFeatured;
private Long totalContent;
private Set<Content> contents = new HashSet<Content>(0);
// Constructors
/** default constructor */
public Author() {
}
// Property accessors
@Id
@GeneratedValue(generator = "Author_SequenceStyleGenerator")
@GenericGenerator(name = "Author_SequenceStyleGenerator", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "Author_SEQ"),
@Parameter(name = "optimizer", value = "hilo"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1") }
)
@Column(name = "id", unique = true, nullable = false, length = 11)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name", length = 50)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Temporal(TemporalType.DATE)
@Column(name = "birth_date", length = 10)
public Date getBirthDate() {
return this.birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
@Temporal(TemporalType.DATE)
@Column(name = "death_date", length = 10)
public Date getDeathDate() {
return this.deathDate;
}
public void setDeathDate(Date deathDate) {
this.deathDate = deathDate;
}
@Column(name = "bio", length = 65535)
public String getBio() {
return this.bio;
}
public void setBio(String bio) {
this.bio = bio;
}
@Column(name = "wiki_url", length = 128)
public String getWikiUrl() {
return this.wikiUrl;
}
public void setWikiUrl(String wikiUrl) {
this.wikiUrl = wikiUrl;
}
@Column(name = "image_path", length = 50)
public String getImagePath() {
return this.imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
@Column(name = "is_featured")
public Boolean getIsFeatured() {
return this.isFeatured;
}
public void setIsFeatured(Boolean isFeatured) {
this.isFeatured = isFeatured;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "author")
public Set<Content> getContents() {
return this.contents;
}
public void setContents(Set<Content> contents) {
this.contents = contents;
}
@Transient
public Long getTotalContent() {
return totalContent;
}
public void setTotalContent(Long totalContent) {
this.totalContent = totalContent;
}
}
}
答案 1 :(得分:2)
如果没有明确指定每个实体的序列的唯一原因是您希望在不支持序列的数据库上使用DDL,那么这可能是您的解决方案:
@Id
@SequenceGenerator(name = "your_table_id_seq", sequenceName = "your_table_id_seq")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "your_table_id_seq")
@Column(name = "your_table_id")
public Long getId() {
return id;
}
这适用于没有序列的数据库(策略AUTO)。