我可以配置 Hibernate 默认为每个表创建单独的序列吗?

发布于 2024-11-19 08:20:48 字数 227 浏览 8 评论 0原文

Hibernate 默认情况下会创建一个全局序列,用于为所有表生成 id(在 PostgreSQL 的情况下),恕我直言,它的扩展性非常差。尽管我可以为每个实体类型指定要使用的序列,但我不喜欢这样做。我不喜欢显式命名序列并强制使用序列作为生成器策略,因为我希望 hibernate 为可能根本不支持序列的数据库生成 DDL。单个全局序列还使得无法使用 32 位 int 作为主键,这意味着我必须将所有 int id 转换为 long 类型。

Hibernate by default creates a globel sequence which is used to generate ids for all tables, (in the case for PostgreSQL) which scales very bad IMHO. Though I can specify for each entity type which sequence to use, I don't like to do it. I don't like to explicit name the sequence and force to use sequence as the generator strategy, because I want hibernate generate DDL for databases which may not support sequence at all. The single global sequence also make it impossible to use 32-bit int as the primary key, which means I must convert all int id(s) to long type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

邮友 2024-11-26 08:20:48

Hibernate 旨在成为独立于数据库的 ORM 解决方案,但在迁移到另一个数据库供应商时出现了一些关键问题。其中之一是底层数据库的自动ID生成。 MySQL、Oracle 和MS SQL Server 都使用不同的技术来为主键生成自动 ID。因此,当我们开始迁移时,我们会面临很多问题和额外的工作,但本不应该如此。

在 Hibernate 3.2.3 之前,Hibernate 没有提供适当的解决方案,但在 3.2.3 版本中,Hibernate 人员使得提供这种可在任何数据库上运行良好的便携式 ID 生成器成为可能。两者如下,

  • org.hibernate.id.enhanced.SequenceStyleGenerator

“可移植性所采用的方法是,您实际上并不关心是否在数据库中实际使用 SEQUENCE;您可以通过它来实现可移植性。”实际上,您只需要类似序列的值生成。在支持 SEQUENCES 的数据库上,SequenceStyleGenerator 实际上将使用 SEQUNCE 作为值生成器;对于那些不支持SEQUENCES的数据库,它将使用单行表作为值生成器,但具有与SEQUENCE值生成器相同的特性(即它始终在单独的事务中处理序列表) ”。

  • org.hibernate.id.enhanced.TableGenerator

虽然没有专门针对可移植性,但 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;
 }

}
}

Hibernate meant to be Database independent ORM solution, but while migrating to another database vendor some key issues arrives. One of them is Auto ID generation of underlying database. MySQL, Oracle & MS SQL Server all uses different techniques to generate auto ID for primary keys. So, when we start migrating we face lot of issues, extra work which should not be the case.

Prior Hibernate 3.2.3 there was no proper solution by the Hibernate, but in version 3.2.3 Hibernate guys made it possible to offer such portable ID generator which works well on any database. The two are followings,

  • org.hibernate.id.enhanced.SequenceStyleGenerator

“the approach it takes to portability is that really you dont care whether you are physically using a SEQUENCE in the database; really you just want a sequence-like generation of values. On databases which support SEQUENCES, SequenceStyleGenerator will in fact use a SEQUNCE as the value generator; for those database which do not support SEQUENCES, it will instead use a single-row table as the value generator, but with the same exact charecteristics as a SEQUENCE value generator (namely it deals with the sequence table in a separate transaction at all times)”.

  • org.hibernate.id.enhanced.TableGenerator

while not specifically targetting portability, TableGenerator can certainly be used across all databases. It uses a multi-row table where the rows are keyed by a (configurable) sequence_name column; one approach would be to have each entity define a unique sequence_name value in the table to segment its identifier values. It grew out of the older org.hibernate.id.MultipleHiLoPerTableGenerator and uses basically the same table structure. However, while MultipleHiLoPerTableGenerator inherently applies a hi-lo algorithm to the value generation, this new TableGenerator was added to be able to take advantage of the pluggable optimizers.

Example Entity Which usage, Hibernate's Sequences across all databases.

@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;
 }

}
}
岁月苍老的讽刺 2024-11-26 08:20:48

如果没有显式指定每个实体的序列的唯一原因是您想要在不支持序列的数据库上使用 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)。

If the only reason for not explicitly specifying the sequence for each entity is you wanting to use the DDL on databases not supporting sequences, this might be solution for you:

@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;
}

This is going to work for databases w/o sequences (the strategy AUTO).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文