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

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


person Xiè Jìléi    schedule 09.07.2011    source источник


Ответы (2)


Hibernate задумывался как решение ORM, независимое от базы данных, но при переходе на базу данных другого поставщика возникают некоторые ключевые проблемы. Одним из них является автоматическая генерация идентификатора базовой базы данных. MySQL, Oracle и MS SQL Server используют разные методы для создания автоматического идентификатора для первичных ключей. Итак, когда мы начинаем миграцию, мы сталкиваемся с множеством проблем, дополнительной работой, которой быть не должно.

До Hibernate 3.2.3 не было подходящего решения от Hibernate, но в версии 3.2.3 ребята из Hibernate сделали возможным предложить такой портативный генератор идентификаторов, который хорошо работает с любой базой данных. Два следующие,

  • org.hibernate.id.enhanced.SequenceStyleGenerator

«Подход к переносимости заключается в том, что на самом деле вам все равно, используете ли вы физически ПОСЛЕДОВАТЕЛЬНОСТЬ в базе данных; на самом деле вам просто нужна генерация значений в виде последовательности. В базах данных, поддерживающих ПОСЛЕДОВАТЕЛЬНОСТИ, SequenceStyleGenerator фактически будет использовать ПОСЛЕДОВАТЕЛЬНОСТЬ в качестве генератора значений; для тех баз данных, которые не поддерживают ПОСЛЕДОВАТЕЛЬНОСТИ, вместо этого будет использоваться таблица с одной строкой в ​​качестве генератора значений, но с теми же точными характеристиками, что и у генератора значений ПОСЛЕДОВАТЕЛЬНОСТИ (а именно, он всегда работает с таблицей последовательностей в отдельной транзакции) ».

  • org.hibernate.id.enhanced.TableGenerator

Хотя TableGenerator не нацелен на переносимость, его, безусловно, можно использовать во всех базах данных. Он использует многострочную таблицу, в которой строки имеют ключ (настраиваемый) столбец sequence_name; один из подходов заключается в том, чтобы каждый объект определял уникальное значение sequence_name в таблице для сегментации значений своего идентификатора. Он вырос из более старого org.hibernate.id.MultipleHiLoPerTableGenerator и использует в основном ту же структуру таблицы. Однако, хотя MultipleHiLoPerTableGenerator по своей сути применяет алгоритм «привет-ниже» к генерации значений, этот новый TableGenerator был добавлен, чтобы иметь возможность использовать преимущества подключаемых оптимизаторов.

Пример объекта, который использует Hibernate Sequences во всех базах данных.

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

}
}
person Faisal Basra    schedule 09.04.2012
comment
Начальное описание в этом посте является вырезкой и вставкой от автора исходного кода Стива Эберсоула, который написал об этой функции в блоге по адресу in.relation.to/2082.lace Подробнее см. здесь. - person Jon Adams; 21.06.2012
comment
Да, описание взято из официального документа hibernate. - person Faisal Basra; 27.06.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).

person ishi    schedule 31.10.2012