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