Hibernate problem z primary key

0

Witam,
mam pewien problem z kluczami prywatnymi. A mianowicie mam takie trzy klasy.

@Entity
@Table (name = "Kategorie")
public class Kategoria {
	
	@Id @Column (name = "Id_kategorii") @GeneratedValue (strategy = GenerationType.AUTO) 
	private int idKategoria;
	@Column (name = "Kategoria", unique = true)
	String nazwa;
	
	
	public int getIdKategoria() {
		return idKategoria;
	}
	public void setIdKategoria(int idKategoria) {
		this.idKategoria = idKategoria;
	}
	public String getNazwa() {
		return nazwa;
	}
	public void setNazwa(String nazwa) {
		this.nazwa = nazwa;
	}

}
@Entity
@Table (name="Rodzaj_produktu")
public class Rodzaj {
	
	@Id @Column (name = "Id_rodzaju") @GeneratedValue (strategy = GenerationType.AUTO)
	private int idRodzaj;
	
	@Column (name="Nazwa")
	private String nazwa;
	
	public int getIdRodzaj() {
		return idRodzaj;
	}
	public void setIdRodzaj(int idRodzaj) {
		this.idRodzaj = idRodzaj;
	}
	public String getNazwa() {
		return nazwa;
	}
	public void setNazwa(String nazwa) {
		this.nazwa = nazwa;
	}
}
@Entity
@Table (name = "Producenci")
public class Producent {
	
	@Id @Column (name = "Id_producenta") @GeneratedValue (strategy = GenerationType.AUTO) 
	private int idProducent;

	@Column (name = "Producent", unique = true)
	String nazwa;
	
	public int getIdProducent() {
		return idProducent;
	}
	public void setIdProducent(int idProducent) {
		this.idProducent = idProducent;
	}
	public String getNazwa() {
		return nazwa;
	}
	public void setNazwa(String nazwa) {
		this.nazwa = nazwa;
	}
	
	

}

i dane do tabelek przez nie stworzone wprowadzam pomocą takiego okna http://www.fotosik.pl/pokaz_obrazek/pelny/3b54d5384bffc88f.html

i problem jest taki, że jak dodaje rodzaj potem producenta a następnie kategorię to id w tabelkach jest takie:
id w rodzaj =1
id w producent = 2
id w kategoria = 3

a wszędzie powinno być równe 1 bo to przecież pierwsze wpisy do tabeli. Mam nadzieję, że dobrze wyjaśniłem problem. Proszę o rady i sugestie.

Dodam, że baza danych to postgre.

0

Wyglada na to ze GenerationStrategy.AUTO dla bazy ktorej uzywasz korzysta ze wspolnej seqkencji (ewentualnie, stowrzyl sobie wlasna tabelke albo cos). Masz gdzies tam jakas nowa nieznana ci tabelke?

0

Jest jedna z której na razie nie korzystam nazywa się asortyment. I ona jest mi znana ale na razie pusta.

0

Widzę, że nikt nie ogarnia tematu :-(

0

Przeciez dostałeś odpowiedź. Skoro sie tak dzieje to znaczy ze strategia generacji kluczy tak śmiesznie działa, widocznie ma tam jedna sekwencje i tyle. Zmień strategię na inną na przykład na GenerationType.IDENTITY

0

wybierając sekwencje do generowania kluczy możesz zdefiniować nazwę sekwencji - widocznie nie konfigurując tego dalej wykorzystana jest tylko jedna sekwencja

0

Mam pytanko odnośnie powyższego tematu. Czytałem gdzieś (ale nie jestem tego pewien bo to był jakiś post) że mechanizm @GeneratedValue(strategy=SEQUENCE, generator="name_1") opiera się na mechanizmie (właściwości) wbudowanym w bazę danych a nie jest elementem serwera JEE. Czy to prawda?
Jeżeli tak to w bazie danych (np. MySQL) powinna być jakaś komenda uruchamiająca ten mechanizm (rodzaj Constraint??). Czy w takim razie, jeżeli wszystko powyższe jest prawdą, to czy gdy taki mechanizm zostanie raz uruchomiony dla danej tabeli przez serwer JEE podczas używania klasy encji JPA na tym serwerze (z taką adnotacją generowania PK) to czy jest on (ten mechanizm) potem aktywny dla innych aplikacji (nie JPA z JEE) które modyfikowałby tą tabelę dodając rekordy?
Innymi słowy czy różne aplikacje wspólnie zachowają ciągłość i spójność numerowania nowo tworzonych rekordów dla tej tabeli?

0

Niektore bazy nie maja sekwencji (sqlserver?), niektore nie maja kolumn identity (oracle), jeszcze inne nie maja czegos innego. Sam server Jaca EE nic nie 'wlacza', on tylko jest jakby furtka na polaczenia do bazy - co robi aplikacja to jej sprawa. Jedyna z tego co sie orientuje prawdziwie przenosna strategia jest 'table', czyli orm zrobi sobie tabelke z paroma kolumnami, w ktorej rekordy beda symulowac sekwencje. Generowanie klucza polega na select z wiersza dla danej tabelki. Np. tak wyglada taka tabelka (powiedzmy ze ma nazwe SEQ):
TABLE_NAME|CURRENT_VALUE|
tabela_1 | 10 |
tabela_2 | 17 |
tabela_4 | 190 |
Teraz, jak wstawiasz cos do tabela_1, to provider robi:
select current_value from seq where table_name = 'tabela_1'
zapisuje sobie gdzies te 10, alokuje ilestam (mozna ustawic), dajmy na to 10, i zaraz wola:
update seq set current_value = 20 where table_name = 'tabela_1'
i ma w puli 10 id do rozporzadzenia. Taka alokacja moze byc co 1 id, ale i co 1000, jak sie ustawi. Ogolnie im mniej zapytac tym lepiej, ale czasami sie nie da.

0

Dzięki za info.
Dobrze że poruszyłeś temat strategii TABLE bo właśnie nad tym siedziałem i nie wszystko kumałem. Nie rozumiem sensu samej alokacji ani tej jednostki alokacji: atrybut "allocationSize" przy definiowaniu adnotacji @TableGenerator.
Rozumiem sytuację w której gdy dodaję jeden obiekt encji to z tabeli SEQ sczytywana jest wartość nowego PK dla tej encji i wpisywana do pola PK encji a w tabeli SEQ powiększana jest wartość pola "tabela_1" o +1. Czyli kolejne rekordy będą miały numery PK: 1, 2, 3, 4 .... .
A jak ustawisz alokację na 10 to chodzi o to że kolejne rekordy dodawane przez persistowane encje JPA beda miały numery 1, 11, 21, 31.. ? A przerwy w numeracji są do mojego wykorzystania poza mechanizmem JPA?

I jeszcze pytanko o samo działanie tego mechanizmu z tabelą. Jeżeli stworzę dwie encje JPA (i persistuję) dla klasy encji oznaczonej @GeneratedValue(strategy=TABLE) za pomocą konstruktora bez podawania numerów PK, to rozumiem, że dopóki nie zostaną one flushowane to żadne numery PK z tabeli SEQ nie zostaną im przypisane? Będą miały domyślne wartości np. 0. Dopiero flushowanie otworzy transakcje w bazie i spowoduje przypisanie im numerów z SEQ? Czyli to jaki numer będzie miał dany obiekt encji będzie zależało od kolejności jako który ten obiekt był Persistowany w kodzie ?

1

Alokacja sluzy do cachowania, jak napisalem. Przykladowo, mamy allocationSize = 1, wtedy aplikacja musi za kazdym razem gdy zapisuje encje danego typu robic select z tej bazy, pozniej update - ale po co? Mozna zrobic taki select radziej, np. co 100, zapisac do kolumny value n+100 i trzymac te 100 w puli. Zapisywane encje dostaja kolejne numerki, i gdy pula sie wyczerpie, robi sie kolejny select i update +100. Z tego wynika, ze jest 100 razy mniej selectow i updatow, co przy aplikacji zapisujacej i kasujacej bardzo duzo encji moze miec znaczny wplyw na szybkosc aplikacji.

Co do tego kiedy id jest dostepne: pewnosc jest tylko, ze po tym, gdy nastapi flush lub commit transakcji (np. dla IDENTITY, poniewaz to robi juz sama baza danych). Zaleznie od uzywanej strategii, moze to nastapic wczesniej, ale nie powinienes sie na tym opierac, bo to moze byc nieprzenosne. Tutaj pare cytatow:

JPA 2.0 specs:
These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred (which may be at the end of the transaction). Generated primary key values are available in the PostPersist method.

Pro JPA2:
Once the identifier value is obtained, the provider will insert it into the newly persisted entity; however, depending on the way it is generated, it might not actually be present in the object until the entity has been inserted in the database. In other words, the application cannot rely on being able to access the identifier until after either a flush has occurred or the transaction has completed.

Pro JPA2:
Another difference, hinted at earlier, between using IDENTITY and other id generation strategies is that the identifier will not be accessible until after the insert has occurred. Although no guarantee is made about the accessibility of the identifier before the transaction has completed, it is at least
possible for other types of generation to eagerly allocate the identifier.

Ostatni fragment mowi ze jest to mozliwe, ale tak byc nie musi - wiec uwazaj.

Jeszcze jedna rzecz: alokacja z duza wartoscia moze powodowac duze dziury. Np. startujemy aplikacje, pobieramy ostatnia wartosc (0), dodajemy 1000, zapisujemy 1000, po czym stopujemy aplikacje, uruchamiamy znowu, pobieramy ostatnia wartosc - 1000! Nie jest to jednakze problem w wiekszosci przypadkow, najlepiej zapomnij o tych kluczach ze istnieja, a juz na pewno nie zajmuj sie tym czy sa dziury czy nie.

0

Wielkie dzięki. Zajarzyłem.
Mam ściągniętą specyfikacje do JPA 2 (486 str.) ale w rozdziale o TableGenerator Annotation jest tylko tabelka z opisanymi powierzchownie atrybutami ustawień np:
"allocationSize - (Optional) The amount to increment by when allocating numbers from the generator."
I jak tu z tego wykumać o co chodzi i jak to działa?
Powinni to jakoś opisać.
No ale temat z głowy. Dzięki.

0

Tak specyfikacje sa z reguly dosc suche i nie tlumacza slowa po slowie. Tutaj kluczem jest 'alokacja' - provider bierze sobie (alokuje) X id; to inkrementowanie to wartosc o jaka jest robiony ten update.
Zgadza sie, nie zawsze jest to wszystko jasne, ale nie wiem czy nie jest to gdzies indziej opisane. Poza tym, po to sa inne pozycje (np. wspomniana Pro JPA2 - naprawde warta polecenia) zeby tlumaczyly, co specyfikacja chce powiedziec ;d

0

Sprawdzę to Pro JPA2 bo pierwsze słyszę.
Dzięki.
Właściwie to aby dowiedzieć sie jak coś działa w tym JPA to trzeba pisać małe programiki testowe i sprawdzać. Jak przeczytałem sobie dokumentację o Optimistic i Pessimistic Lock to nie wiedziałem jak to realnie działa (czyli reakcja bazy na np. konkretną metodę lokującą np. "find(prams, LockType)"). Dopiero jak przewaliłem te Locki na kilkunastu przykładach to jakiś obraz zaczął się wyłaniać.

0

Coś jeszcze mi przyszło do głowy w temacie TableGenerator.
Select i update wartości w tabeli z numerami PK (SEQ) musi być chyba dokonywany przez JPA Providera w krótkiej, osobnej, natychmiast committowanej transakcji, nie mającej nic wspólnego z transakcją główną zachodzącą dla tworzonych i persistowanych obiektów encji JPA. Inaczej pomiędzy Selectem i Updatem jakiś inny wątek mógłby próbować wykonać swoje pobranie numeru PK i update (też przez tego JPA Providera) i namieszać w numeracji. Musi tu być wprowadzona jakaś izolacja w działaniu JPA Providera.

0

Pro JPA2:
■ TIP The provider might allocate identifiers within the same transaction as the entity being persisted or in a
separate transaction. It is not specified (...)

Tak naprawde to to jest niewazne dla ciebie, po prostu uzywaj i ufaj ze dziala. Zaloze sie ze kazdy provider robi inaczej.

0

No tak, nie ma co za bardzo grzebać w bebechach ....

1 użytkowników online, w tym zalogowanych: 0, gości: 1