Hibernate задумывался как независимое от базы данных решение ORM, но при переходе на другого поставщика базы данных возникают некоторые ключевые проблемы. Одним из них является автоматическая генерация идентификатора базовой базы данных. MySQL, Oracle и MS SQL Server используют разные методы для генерации автоматического идентификатора для первичных ключей. Поэтому, когда мы начинаем миграцию, мы сталкиваемся с множеством проблем, дополнительной работой, которой не должно быть.
До Hibernate 3.2.3 не было правильного решения от Hibernate, но в версии 3.2.3 ребята из Hibernate сделали возможным предложить такой портативный генератор идентификаторов, который хорошо работает на любой базе данных. Два следующие,
- 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;
}
}
}