【问题标题】:Can I configure Hibernate to create separate sequence for each table by default?我可以将 Hibernate 配置为默认为每个表创建单独的序列吗?
【发布时间】:2011-10-01 18:44:26
【问题描述】:

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

【问题讨论】:

    标签: hibernate orm code-generation ddl


    【解决方案1】:

    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 以便能够利用可插入优化器。

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

    【讨论】:

    • 这篇文章的开头描述是从原始代码作者 Steve Ebersole 中剪切和粘贴的,他在 in.relation.to/2082.lace 上写了关于此功能的博客,了解更多详细信息。
    • 是的,描述来自hibernate官方文档。
    【解决方案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)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 2011-08-11
      • 2011-04-05
      • 1970-01-01
      相关资源
      最近更新 更多