Can I configure Hibernate to create a separate sequence for each table by default?

By default, hibernation creates a sequence of globules that is used to generate identifiers for all tables (in the case of PostgreSQL), which scales very poorly IMHO. Although I can indicate for each entity type which sequence to use, I do not like to do this. I don't like to explicitly specify a sequence and the power to use a sequence as a generator strategy, because I want hibernate to generate DDL for databases that may not support a sequence at all. A single global sequence also makes it impossible to use a 32-bit int as a primary key, which means that I have to convert all int identifiers to long.

+6
source share
2 answers

Hibernate means an ORM-independent database solution, but there are some key issues when migrating to another database provider. One of them is the generation of an Auto ID base database. MySQL, Oracle, and MS SQL Server use different methods to generate an automatic identifier for primary keys. So, when we start to migrate, we are faced with many problems, additional work that should not be.

Prior Hibernate 3.2.3 there was no right Hibernate solution, but in version 3.2.3 the guys from Hibernate allowed us to offer such a portable identifier generator that works well in any database. These two are:

  • org.hibernate.id.enhanced.SequenceStyleGenerator

โ€œThe approach that portability requires is that you donโ€™t really care if you physically use SEQUENCE in a database, you just want to generate sequence type values. In databases that support SEQUENCES, SequenceStyleGenerator actually uses SEQUNCE in as a value generator, for those databases that do not support SEQUENCES, instead, it will use a single row table as a value generator, but with the same exact characteristics as the SEQUENCE value generator (namely, it deals with a sequence table in a separate transaction at all times). "

  • org.hibernate.id.enhanced.TableGenerator

although not specifically designed for portability, TableGenerator can certainly be used in all databases. It uses a table with several rows, in which rows have the key (custom) sequence_name; one approach would be for each entity to define a unique sequence_name value in the table to segment its identifier values. It grew out of the old org.hibernate.id.MultipleHiLoPerTableGenerator and uses basically the same table structure. However, while the MultipleHiLoPerTableGenerator inherently uses the hi-lo algorithm to generate values, this new TableGenerator has been added to be able to use optimizable optimizers.

Entity example. What a use, Hibernate Sequences for 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; } } } 
+4
source

If the only reason you do not explicitly specify a sequence for each object is to use DDL for databases that do not support sequences, this might be the 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 will work for databases without sequences (AUTO strategy).

+2
source

Source: https://habr.com/ru/post/892379/


All Articles