Określanie indeksu (nieunikatowy klucz) za pomocą JPA

100

Jak zdefiniujesz pole, np. emailJako posiadające indeks przy użyciu adnotacji JPA. Potrzebujemy nieunikalnego klucza, emailponieważ w tym polu dziennie są dosłownie miliony zapytań, a bez klucza jest trochę powolny.

@Entity
@Table(name="person", 
       uniqueConstraints=@UniqueConstraint(columnNames={"code", "uid"}))
public class Person {
    // Unique on code and uid
    public String code;
    public String uid;

    public String username;
    public String name;
    public String email;
}

Widziałem adnotację specyficzną dla hibernacji, ale staram się unikać rozwiązań specyficznych dla dostawcy, ponieważ wciąż decydujemy między hibernacją a jądrem danych.

AKTUALIZACJA:

Od JPA 2.1 możesz to zrobić. Zobacz: Adnotacja @Index jest niedozwolona w tej lokalizacji

Jakub
źródło
6
Byłoby wspaniale, gdybyś mógł zaktualizować odpowiedź, aby ludzie uznali, że dzięki JPA 2.1 naprawdę jest na to sposób
borjab
2
Dlaczego nie przyjmiesz najbardziej pozytywnej odpowiedzi?
naXa

Odpowiedzi:

208

Z JPA 2.1 powinieneś to zrobić.

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity
@Table(name = "region",
       indexes = {@Index(name = "my_index_name",  columnList="iso_code", unique = true),
                  @Index(name = "my_index_name2", columnList="name",     unique = false)})
public class Region{

    @Column(name = "iso_code", nullable = false)
    private String isoCode;

    @Column(name = "name", nullable = false)
    private String name;

} 

Aktualizacja : jeśli kiedykolwiek będziesz musiał tworzyć i indeksować z dwiema lub więcej kolumnami, możesz użyć przecinków. Na przykład:

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{
borjab
źródło
Dzięki Alvinowi za odpowiedź. (+1 głos). Ale musiałem poszukać kilku rzeczy i mam nadzieję, że ten przykład może ułatwić ci życie
borjab
Dokładnie to, czego szukałem - prosty i czysty kod wycięty - nie tylko opisujący całość. Dzięki +1.
DominikAngerer
2
@borjab - czy możesz mi podpowiedzieć, gdzie mogę znaleźć „oficjalny” przykład lub specyfikację użycia @Indexadnotacji w @Tableadnotacji? Szukałem JSR 338, ale go tam nie znalazłem. Twój post jest dla mnie bardzo przydatny.
JimHawkins
2
@Ulrich Niezupełnie oficjalne dokumentacja, ale blog oracle blogs.oracle.com/arungupta/entry/jpa_2_1_schema_generation
borjab
Zastanawiam się, czy jeśli mam kolumnę z @Column (unique = true), czy zostanie ona scalona z listą indeksów (ponieważ unique jest również indeksem)?
wkrueger
34

Unikalny, ręcznie wybrany zbiór adnotacji w indeksie

= Dane techniczne =

= ORM Frameworks =

= ORM dla Androida =

= Inne (trudne do skategoryzowania) =

  • Realm - Alternatywna baza danych dla iOS / Android: Adnotacja io.realm.annotations.Index;
  • Empire-db - lekka, ale potężna relacyjna warstwa abstrakcji DB oparta na JDBC. Nie ma definicji schematu za pomocą adnotacji;
  • Kotlin NoSQL (GitHub) - reaktywny i bezpieczny typ DSL do pracy z bazami danych NoSQL (PoC): ???
  • Zręczne - reaktywne funkcjonalne mapowanie relacyjne dla Scala. Nie ma definicji schematu za pomocą adnotacji.

Po prostu wybierz jedną z nich.

naXa
źródło
31

JPA 2.1 (wreszcie) dodaje obsługę indeksów i kluczy obcych! Zobacz ten blog, aby uzyskać szczegółowe informacje. JPA 2.1 jest częścią Java EE 7, która jest obecnie.

Jeśli lubisz żyć na krawędzi, możesz pobrać najnowszą migawkę dla eclipselink z ich repozytorium maven (groupId: org.eclipse.persistence, artifactId: eclipselink, wersja: 2.5.0-SNAPSHOT). Tylko dla adnotacji JPA (które powinny działać z każdym dostawcą, gdy obsługują 2.1) użyj artifactID: javax.persistence, wersja: 2.1.0-SNAPSHOT.

Używam go do projektu, który nie zostanie ukończony przed jego wydaniem i nie zauważyłem żadnych okropnych problemów (chociaż nie robię z nim nic zbyt skomplikowanego).

AKTUALIZACJA (26 września 2013 r.): Obecnie wersje eclipselink do wydania i wydania kandydatów do wydania są dostępne w centralnym (głównym) repozytorium, więc nie trzeba już dodawać repozytorium eclipselink w projektach Maven. Najnowsza wersja to 2.5.0, ale obecna jest również wersja 2.5.1-RC3. Przerzuciłbym się na 2.5.1 JAK NAJSZYBCIEJ z powodu problemów z wersją 2.5.0 (rzeczy modelgen nie działają).

Alvin Thompson
źródło
9

W JPA 2.1 musisz wykonać następujące czynności

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity(name="TEST_PERSON")
@Table(
    name="TEST_PERSON", 
    indexes = {
       @Index(name = "PERSON_INDX_0", columnList = "age"),
       @Index(name = "PERSON_INDX_1", columnList = "fName"),
       @Index(name = "PERSON_INDX_1", columnList = "sName")  })
public class TestPerson {

    @Column(name = "age", nullable = false)
    private int age;

    @Column(name = "fName", nullable = false)
    private String firstName;

    @Column(name = "sName", nullable = false)
    private String secondName;

    @Id
    private long id;

    public TestPerson() {
    }
}

W powyższym przykładzie tabela TEST_PERSON będzie miała 3 indeksy:

  • unikalny indeks identyfikatora klucza podstawowego

  • indeks na AGE

  • indeks złożony na FNAME, SNAME

Uwaga 1: Indeks złożony uzyskuje się, mając dwie adnotacje @Index o tej samej nazwie

Uwaga 2: Nazwę kolumny określasz w columnList, a nie w fieldName

James Clayton
źródło
5

Naprawdę chciałbym móc określić indeksy bazy danych w ustandaryzowany sposób, ale niestety nie jest to częścią specyfikacji JPA (może dlatego, że specyfikacja JPA nie wymaga obsługi generacji DDL, co jest rodzajem blokady drogowej dla taka funkcja).

Musisz więc polegać na rozszerzeniu specyficznym dla dostawcy. Hibernate, OpenJPA i EclipseLink wyraźnie oferują takie rozszerzenie. Nie mogę potwierdzić dla DataNucleus, ale ponieważ definicja indeksów jest częścią JDO, myślę, że tak.

Naprawdę mam nadzieję, że obsługa indeksu zostanie ustandaryzowana w kolejnych wersjach specyfikacji i tym samym jakoś nie będzie się zgadzać z innymi odpowiedziami, nie widzę żadnego powodu, aby nie umieszczać czegoś takiego w JPA (zwłaszcza, że ​​baza danych nie zawsze jest pod twoją kontrolą) dla optymalnej obsługi generacji DDL.

Przy okazji sugeruję pobranie specyfikacji JPA 2.0.

Pascal Thivent
źródło
4

O ile mi wiadomo, nie istnieje sposób określania indeksów przez dostawców między JPA. Jednak zawsze możesz utworzyć je ręcznie bezpośrednio w bazie danych, większość baz danych pobierze je automatycznie podczas planowania zapytań.

Tassos Bassoukos
źródło
2
lol, zakładając, że masz DBA, którzy wykonują pracę DBA (:
Jacob
3
Wydaje mi się nieco dziwne, że istnieje sposób na wykonanie „unikatowego”, ale nie sposób na wykonanie indeksu.
Jacob
7
@Jacob - Cóż, ważne jest, aby wiedzieć na poziomie aplikacji, czy jakieś pole będzie unikalne, czy nie. Z drugiej strony indeksy służą do optymalizacji dostępu do bazy danych. Nie ma potrzeby (o ile widzę), aby wiedzieć, czy kolumna jest indeksem w warstwie java, czy nie. Jak powiedziałeś, administrator może ustawić indeks, jeśli wydaje się, że dana kolumna skorzystałaby na tym.
Java Drinker
1
@Jacob, nie ma obsługi indeksu, ponieważ jest to po prostu optymalizacja (zwykle ważna, ale nadal optymalizacja). OTOH, jeśli pole (lub zestaw pól) jest unikalne lub nie, zależy od modelu i wpłynie na poprawność. Ponadto nie ma potrzeby posiadania pełnej bazy danych o wartości 200 USD / godz., Zwykle wystarczają proste instrukcje dotyczące tworzenia indeksu.
Tassos Bassoukos
8
WZP 2.1 określajavax.persistence.Index
Lukas Eder
2

EclipseLink dostarczył adnotację (np. @Index ) w celu zdefiniowania indeksu w kolumnach. Oto przykład jego użycia. Część przykładu jest dołączona ...

Pola firstName i lastName są indeksowane razem i indywidualnie.

@Entity
@Index(name="EMP_NAME_INDEX", columnNames={"F_NAME","L_NAME"})  // Columns indexed together
public class Employee{
    @Id
    private long id;

    @Index                      // F_NAME column indexed
    @Column(name="F_NAME")
    private String firstName;

    @Index                      // L_NAME column indexed
    @Column(name="L_NAME")
    private String lastName;
    ...
}
Nathan
źródło
1

OpenJPA umożliwia określenie niestandardowych adnotacji w celu zdefiniowania indeksu właściwości.

Szczegóły tutaj .

ekspert
źródło
0

Nie można tego zrobić za pomocą adnotacji JPA. I to ma sens: gdy UniqueConstraint jasno definiuje reguły biznesowe, indeks jest tylko sposobem na przyspieszenie wyszukiwania. Więc powinno to być naprawdę zrobione przez administratora.

Thierry-Dimitri Roy
źródło
0

To rozwiązanie jest dla EclipseLink 2.5 i działa (przetestowane):

@Table(indexes = {@Index(columnList="mycol1"), @Index(columnList="mycol2")})
@Entity
public class myclass implements Serializable{
      private String mycol1;
      private String mycol2;
}

Zakłada to kolejność rosnącą.

Joe Almore
źródło