我可以配置Hibernate默认为每个表创建单独的序列吗? [英] Can I configure Hibernate to create separate sequence for each table by default?

查看:355
本文介绍了我可以配置Hibernate默认为每个表创建单独的序列吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

默认情况下,Hibernate会创建一个全局序列,用于为所有表生成ids(对于PostgreSQL而言),这会缩放非常糟糕的IMHO。虽然我可以为每个实体类型指定使用哪个序列,但我不喜欢这样做。我不喜欢明确命名序列并强制使用序列作为生成器策略,因为我希望hibernate为可能不支持序列的数据库生成DDL。单个全局序列也使得不可能使用32位int作为主键,这意味着我必须将所有int id转换为long类型。

解决方案

Hibernate意味着与数据库无关的ORM解决方案,但在迁移到另一个数据库供应商时会遇到一些关键问题。其中之一是底层数据库的Auto 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

  • ul>

    虽然没有专门针对可移植性,但TableGenerator当然可以在所有数据库中使用。它使用一个多行表,其中行由(可配置的)sequence_name列键入;一种方法是让每个实体在表中定义唯一的sequence_name值来分割其标识符值。它由早期的org.hibernate.id.MultipleHiLoPerTableGenerator发展而来,基本上使用相同的表结构。然而,虽然MultipleHiLoPerTableGenerator固有地将Hi-Lo算法应用于值生成,但是新添加的TableGenerator可以充分利用可插入优化器的优势。

    示例实体对所有数据库使用Hibernate的序列。

      @Entity 
    @Table(name = author)
    public class Author实现java.io.Serializable {

    // Fields

    private Integer id;
    私人字符串名称;
    私人日期birthDate;
    私人日期deathDate;
    private String bio;
    私人字符串wikiUrl;
    private String imagePath;
    私有布尔isFeatured;
    private long totalContent;
    私人套餐<内容> contents = new HashSet< Content>(0);

    //构造函数
    $ b $ / **默认构造函数* /
    public作者(){
    }

    //属性访问器
    @Id
    @GeneratedValue(generator =Author_SequenceStyleGenerator)
    @GenericGenerator(name =Author_SequenceStyleGenerator,strategy =org.hibernate.id.enhanced.SequenceStyleGenerator,
    参数= {
    @Parameter(name =sequence_name,value =Author_SEQ),
    @Parameter(name =optimizer,value =hilo),
    @参数(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(){
    返回this.birthDate;
    }

    public void setBirthDate(Date birthDate){
    this.birthDate = birthDate;
    }

    @Temporal(TemporalType.DATE)
    @Column(name =death_date,length = 10)
    public Date getDeathDate(){
    返回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 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.

    解决方案

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

    这篇关于我可以配置Hibernate默认为每个表创建单独的序列吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆