So ein SequenceGenerator ist schon eine feine Sache, vorallem bei der Verwendung von Relationalen Datenbanksystemen á la Oracle. Musste man sich ohne die Vorzüge des ORM (Object-Relational-Mapping) noch mit der händischen Erstellung von Sequenzen zur Incrementierung von Werten herumschlagen, erledigt Hibernate das Ganze voll automatisch mit zwei Zeilen Code.
Die Tücken der Technik
In meinem letzten Projekt zeigte sich jedoch ein interessantes Phänomen: Ich erstellte eine Klasse mit Annotation und einer Autoincrement-Sequence zum Hochzählen der Id.
@Entity @SequenceGenerator(name = "user_seq", sequenceName = "user_id_seq") public class User implements Serializable { ... }
Zunächst schien alles zu funktionieren, als ich aber einige Zeit später in die Datenbank schaute entdeckte ich seltsame Sprünge zwischen den Ids:
id |
name |
age |
50 |
Fred |
31 |
51 |
Harry |
25 |
100 |
Mike |
13 |
101 |
Frank |
46 |
102 |
Richard |
52 |
150 |
Ted |
31 |
151 |
Kyle |
29 |
152 |
Steve |
34 |
153 |
Michael |
42 |
Nach einigem Probieren stellte ich fest, dass die Sprünge stets nach dem Neustart der Anwendung auftraten. Das Problem konnte ich schließlich nach etwas Recherche im Internet ausmachen. Für den SequenceGenerator
existiert ein Parameter allocationSize
, welcher die definierte Sequenz um den angegeben Wert erhöht und anschließend diese Nummern vergibt. Erst wenn alle verbraucht sind, wird die Sequenz erneut aufgerufen. Der Nachteil dieser performanten Vorgehensweise ist, dass bei einem Neustart der Anwendung die zwischengspeicherten Werte verloren gehen und dadurch Lücken zwischen den Id's entstehen. Standardmäßig ist diese Einstellung auf 50 gesetzt, was auch den Abstand in der Datenbank erklärt. Die nachfolgende Einstellung schafft also Abhilfe:
@Entity @SequenceGenerator(name = "user_seq", sequenceName = "user_id_seq" allocationSize=1) public class User implements Serializable { ... }
Nun wird zur Generierung des nächsten Primary-Keys immer die Datenbanksequenz bemüht, was die Performance zwar etwas mindert, jedoch bleiben die Lücken aus.
Links: http://www.galileocomputing.de/artikel/gp/artikelID-328
Nun, es mindert die Performance nicht nur ein bisschen… je nach Traffic / Anzahl gleichzeitigen Sessions ist das sogar ein wichtiger Bottleneck. Daher gibt es diesen Parameter, den die meisten PHP, Ruby, … Programmierer allerdings überhaupt nicht kennen. 😉 Und wen interessieren schon Sprünge in einer 64Bit Zahl.