Могу ли я настроить Hibernate для создания отдельной последовательности для каждой таблицы по умолчанию? - PullRequest
6 голосов
/ 09 июля 2011

Hibernate по умолчанию создает глобальную последовательность, которая используется для генерации идентификаторов для всех таблиц (в случае PostgreSQL), что очень плохо масштабируется IMHO. Хотя я могу указать для каждого типа сущности, какую последовательность использовать, я не люблю это делать. Мне не нравится явно называть последовательность и заставлять использовать последовательность в качестве стратегии генератора, потому что я хочу, чтобы hibernate генерировал DDL для баз данных, которые могут вообще не поддерживать последовательность. Единственная глобальная последовательность также делает невозможным использование 32-битного int в качестве первичного ключа, а это означает, что я должен преобразовать все int id (и) в тип long.

Ответы [ 2 ]

4 голосов
/ 09 апреля 2012

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

}
}
2 голосов
/ 31 октября 2012

Если единственная причина, по которой вы не указали явно последовательность для каждого объекта, это то, что вы хотите использовать 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).

...