Najlepszy sposób na generowanie id

0

Jaki jest najlepszy sposób na generowanie id (musi być unikatowe jakby ktoś nie wiedział) , które będzie w miarę czytelne i łatwe w użyciu (UUID odpada) i niezależne od frameworka (id generowanie przez Hibernate również odpada).

8

Nie wiem, pod jakimi względami najlepszy. Jeśli pod względem prostoty i czytelności, to proponuję:

int nextId() {
   return counter++;
}
17

Napisz dlaczego UUID odpada. To może dowiemy się co będzie najlepsze.

Moja propozycja:

int nextId() {
   return 1;
}

Nie jest co prawda unikatowe (nie było takiego wymogu), ale czytelne, łatwe w użyciu i bezpieczne wątkowo. Na niewielkie ilości obiektów (maks 1) całkiem się nada.

0

@Charles_Ray: Nie chodzi mi o id zapisywane w pamięci. Wydawało mi się to oczywiste.

@jarekr000000: Twoim zdaniem coś takiego jak "237e9877-e79b-12d4-a765-321741963000" jest czytelne i łatwe w użyciu? Moim zdaniem nie bardzo, dlatego szukam alternatyw o ile oczywiście istnieją.
Chodzi oczywiście o unikalne id. Dopisałem ten warunek w głównym poście.

3

@Sampeteq:

które będzie w miarę czytelne

Tylko, że ID nie ma być czytelne a spełniać swoją rolę. To tak jak byś od pięściarza wymagał aby wypowiadał się jak ktoś po polonistyce.

jest czytelne i łatwe w użyciu?

No ale co ma tutaj czytelność? No i dlaczego by nie miało być łatwe w użyciu? To będzie zapisywał komputer i czy to będzie 1, czy HJKFHJKFHDK to nie ma znaczenia dopóki będzie spełniało swoją rolę.

Jaki masz przypadek użycia? W sensie, do czego chcesz to wykorzystać?

4
Sampeteq napisał(a):

@jarekr000000: Twoim zdaniem coś takiego jak "237e9877-e79b-12d4-a765-321741963000" jest czytelne i łatwe w użyciu? Moim zdaniem nie bardzo, dlatego szukam alternatyw o ile oczywiście istnieją.
Chodzi oczywiście o unikalne id. Dopisałem ten warunek w głównym poście.

Nie wiem w czym jest problem. Ja widzę w kodzie UUID id albo UUID.randomUUID i jest to czytelne i łatwe w użyciu. Nie widzę potrzeby czytania tego co się wygeneruje jako uuid. Jak mam int x = 42; to nie zaglądam jakie tam są bity zapalone w tym intu.

2

Po co ma być czytelne? Chcesz dzwonić do swoich ulubionych krotek w bazie? Możesz generować na 2 sposoby:

  1. Globalnie unikalne, ale tutaj nie będzie "ładne", bo żeby mieć gwarancję unikalności musi być długie
  2. Sekwencyjnie, czyli licznik, to czy umieszczony w bazie, czy w twoim programie nie ma znaczenia.
1

Po co ma być czytelne? Chcesz dzwonić do swoich ulubionych krotek w bazie?

@piotrpo A widzisz, przerabiałem podobny problem. UUID-u nie są za bardzo customer-friendly, słabo prezentować np. taki numer zamówienia klientowi.

0

A takie jak ma youtube może być? Używają pierwsze 11 znaków base64 z binarnego uuid - potrzeba 22 znaków żeby zakodować cały UUID, ale wystarczy połowa tego jak w przypadku youtube'a żeby uniknąć kolizji przez 18000 lat jeśli każda osoba na świecie generowałaby nowy ID co minutę. Dla spokoju ducha możesz sprawdzić czy już masz taki ID w bazie

6

@Charles_Ray: Jak ktoś wpada na pomysł prezentowania identyfikatora z bazy danych klientowi to powinien się rozpędzić i walnąć głową w ścianę, jak nie pomaga, to czynność powtórzyć. Dla własnego dobra, bo ból jaki nadejdzie w momencie kiedy biznes uzna, że nie, takie identyfikatory nie moga być zwykłym 1, 2, 3, bo potrzebujemy 2021/10/ABS/QWR/4321/0000023 będzie bez porównania większy.
Ale nadal - albo UUID (w dodowlnej formie) i będzie szybko, sprawdzi się dobrze w systemach rozproszonych.
Sekwencyjnie counter++ w dowolnej formie, będzie wolniej i nie zadziała w systemach rozproszonych, bo gdzieś trzeba będzie trzymać ten sekwencyjny licznik i pewnie go jakoś utrwalać, żeby wiedzieć gdzie wystartować jak padnie.

A swoją drogą, to co robi hibernate jest niezależne od frameworku, bo robi to baza danych.

0

są różne sztuczki. Jak trzeba naprawdę unikalnie ale jednak niech to jakoś się indeksuje w bazie, to można takiego guida iterować na czterech ostatnich znakach. Proste , szybkie i działa.

0

Jak ktoś wpada na pomysł prezentowania identyfikatora z bazy danych klientowi to powinien się rozpędzić i walnąć głową w ścianę

@piotrpo spoko, co w takim razie proponujesz ;) nie odnalazłem w Twoim poście rozwiązania. Jak wygenerować taki ID, który można pokazać klientowi?

0

W sumie bez kontekstu dyskusja bez sensu.
Praktycznie mamy kilka głównych czynników, które determinują to jakiego rodzaju identyfikatorów powinniśmy używać.
Mi do głowy przychodzą następujące:

  1. Czy ma znaczenie zajętość identyfikatorów docelowy rozmiar w pamięci co może mieć znaczenie w przypadku dużej ilości obiektów;
  2. Czy ma znaczenie szybkość generowania identyfikatorów;
  3. Czu ma znaczenie bezpieczeństwo ;

W praktyce widzę to np. tak:

  1. W przypadku bardzo dużych ilości obiektów i konieczności optymalizacji miejsca polecałbym zwykły licznik++ ;
  2. W przypadku, gdy ten identyfikator ma być widoczny w sieci i chcemy uniknąć tego, że ktoś nam będzie skanował całą bazę lepiej używać jakieś UUID ;
  3. Jeśli chcemy aby identyfikator dawał jakąś informację o kolejności powstawiania obiektów to licznik++ lub specjalne UUID, które ma taką cechę, że można je właśnie tak sortować.
  4. Jeśli to baza obiektów zoptymalizowana na szybkość działania np. obiekty grafiki 3D to ewidentnie licznik++ ;

Równie skutecznym w większości codziennych przypadków może być prosty generator:

  static function guid ( $length )
  {
    $tmp = '' ;
    for ( $i=1; $i<=$length; $i++ ){
      $tmp .= chr ( rand ( 65, 90 ) ) ;
    }
    return $tmp ;
  }

Dla takiego $length = 8 znaków masz 208 827 064 576 kombinacji

3

@Charles_Ray: Przecież piszę sekwencja. Zwyczajnie uważam, że klucz główny dowolnej tabeli, nie powienien być w żaden sposób wykorzystywany biznesowo. Piszesz sobie jakiś tam system do obsługi zamówień, drukujesz go na raporcie. Po roku firma się rozwija, i potrzebą biznesową jest zmiana ze zwykłego 123, na 2021/123, po kolejnym roku firma się dalej rozwija i chcą, żeby numer miał format "2021/{sklep}/123. W dodatku chcą, żeby numer zawsze się zerował. Jeżeli trzymasz w bazie jakiegoś varchara z numerem dla użytkownika, to zmiana jest banalna, jak używasz wewnętrznego id krotki (klucza głównego), to nagle się okazuje, że musisz przerobić połowę struktury repozytorium.

Jak potrzebujesz jakiegoś sekwencyjnego numeratora, to nie ma cudów - musisz go gdzieś przechowywać i musisz obronić się przed wyścigiem wątków. Jak masz dodatkowo wymóg braku luk w numeracji, to robi się jeszcze ciekawiej, bo transakcja obejmie zarówno zmianę numeru, jak i zapisanie dokumentu. Jak zrealizować tę sekwencję to już osobny problem - czasami wystarczy AtomicInteger, czasami sekwencja w bazie, czasami osobny serwis z jakimś redisem do przechowywania wartości poszczególnych sekwencji.

0

Baza z jedną instancją o niskich wymogach wydajnościowych: autoincremental, sekwencja (Oracle).
Baza z jedną instancją trochę szybsza: hi-low
Baza rozproszona gdzie nie trzeba oszczędzać dysków: UUID (128 bitów)
Baza rozproszona gdzie liczy się każdy bajt: snowflake (64 bity lub więcej).

Wymóg żeby identyfikator był w miarę czytelny w zasadzie ma zastosowanie tylko w pierwszym przypadku.
Wymóg żeby Hibernate tego nie generował - tego nie rozumiem, raczej polecam stosować sprawdzone rozwiązania niż "moje będzie najmojsze".

Uwaga: jest jeszcze kilka antypatternów w tej dziedzinie, wypiszę ku przestrodze na wypadek gdyby OP chciał spróbować swoich możliwości:

  • klucze biznesowe - PESEL, data + nr zamówienia, imię + nazwisko - te dane mogą się zmienić, jeśli ich użyjesz w PK to masz przerąbane
  • tabela generatorów kluczy (nazwa generatora, następna wartość) - zwykle się blokuje przy kilku użytkownikach lub jest po prostu wolna

Polecam przeczytać:
https://dzone.com/articles/7-strategies-for-assigning-ids-to-microservices
https://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557

1

Jeżeli nie muszą być sekwencyjne to np. https://github.com/callicoder/java-snowflake
Generalnie generowanie krótszych ID niż UUID to aktywny obszar badań, nawet w robocie się trochę o to otarłem. Jest dużo algorytmów, dających nie gorsze gwarancje niż UUID ale na Long'u (czyli na połowie bajtów z UUID). Dodatkowo zazwyczaj koduje się takie Long'owe ID przy użyciu np. base32 żeby jeszcze je skrócić potem masz /article/xjdhywye-apple-macbook-notch-is-widely-criticized z xjdhywye jako faktycznym ID.

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