2015-06-09 20 views
8

Ich arbeite an einer Java Anwendung, die CRUD-Operationen tun soll (mit Hibernate 4.3.8) auf zwei verschiedene Datenbanken mit dem gleichen Datenbankschema. Es gibt eine MySQL (Version 5.1.73) und eine Oracle (11g Express Edition Release 11.2.0.2.0 - 64bit) -Datenbank.Hibernate Autoschlüsselgenerierung mit MySQL und Oracle

Java-Klassen mit JPA-Anmerkungen wurden aus den Datenbanktabellen mit Hibernate-Codegenerierung generiert.

Das Problem ist, dass wir jetzt die Notwendigkeit der Verwendung von Auto-Primärschlüsselgenerierung haben und MySQL verwendet GenerationType.IDENTITY und Oracle verwendet GenerationType.SEQUENCE. Außerdem müssen wir in einigen seltenen Fällen den Primärschlüssel manuell einstellen.

Der folgende Code in der annotierten Klasse funktioniert mit automatischer Schlüsselgenerierung für beide Datenbanken, schlägt jedoch fehl, wenn ein Primärschlüssel selbst gesetzt ist.

@GeneratedValue(strategy=GenerationType.AUTO, generator="sequence_generator") 
@SequenceGenerator(name="sequence_generator", sequenceName="SEQUENCE1") 
@Column(name = "id", unique = true, nullable = false) 
public Integer getId() { 
    return this.id; 
} 

Ohne die @GeneratedValue und @SequenceGenerator Anmerkungen ist es möglich, den Primärschlüssel manuell einstellen, aber Auto Generation nicht funktioniert.

+0

dieses [Versuchen Sie manuell festlegen, the value-of-a- Primärschlüssel-in-jpa-generierteWertspalte] [1]. Da gibt es viele Lösungen. [1]: http://stackoverflow.com/questions/12002260/manually-specify-the-value-of-a-primary-key-in-jpa-generatedvalue-column – Volatile

+0

Die Datenbank-zentrierten Lösung in diesem Thread funktioniert nicht für mich, da das Datenbankschema nicht geändert werden sollte. Es gibt andere Leute als mich, die sich darauf verlassen, dass sich das Datenbankschema nicht ändert. Und ich weiß nicht, ob es möglich ist und wie man einen eigenen Custom Id Generator schreibt, der beide Datenbanken MySQL UND Oracle (Identity and Sequence) unterstützt. In allen Beispielen verwenden sie entweder IdentifierGenerator OR Sequencegenerator. –

+1

Diese Frage ist nicht klar. Sagen Sie, dass Sie einige Klassen haben, für die Hibernate Kennungen automatisch generieren und Kennungen anderen Klassen manuell zuweisen soll? Oder möchten Sie, dass Hibernate den Instanzen einer Klasse meistens automatisch Kennungen zuweist, aber in einigen Fällen Kennungen manuell einigen Instanzen derselben Klasse zuweisen möchten? – manish

Antwort

9

Auch wenn Sie GenerationType.AUTO ohne sequenzspezifische Parameter verwendet wird, würden Sie nicht in der Lage sein, zugewiesen Kennungen zu speichern.

Es gibt einige Abhilfen, wenn Sie bereit sind, einige Kompromisse zu machen:

  1. Eine Möglichkeit, zugewiesen Identifikatoren zu wechseln wäre. Sie können UUID Bezeichner verwenden, die sowohl für MySQL als auch für Oracle funktionieren, und Sie können die Werte auch manuell zuweisen.

  2. Eine andere Möglichkeit ist die Verwendung eines benutzerdefinierten Tabellengenerators.

    Zunächst definieren Sie eine identifizierbare Schnittstelle:

    public interface Identifiable<T extends Serializable> { 
        T getId(); 
    } 
    

    Dann erweitern Sie den Tabellengenerator:

    public class AssignedTableGenerator extends TableGenerator { 
    
        @Override 
        public Serializable generate(SessionImplementor session, Object obj) { 
         if(obj instanceof Identifiable) { 
          Identifiable identifiable = (Identifiable) obj; 
          Serializable id = identifiable.getId(); 
          if(id != null) { 
           return id; 
          } 
         } 
         return super.generate(session, obj); 
        } 
    } 
    

    Dieser Generator ist in der Lage zugeordnet Kennungen mit synthetischen erzeugt diejenigen zu mischen:

    doInTransaction(session -> { 
        for (int i = 0; i < 5; i++) { 
         session.persist(new AssignTableSequenceIdentifier()); 
        } 
        AssignTableSequenceIdentifier tableSequenceIdentifier = new AssignTableSequenceIdentifier(); 
        tableSequenceIdentifier.id = -1L; 
        session.merge(tableSequenceIdentifier); 
        session.flush(); 
    }); 
    

    Erzeugen der folgenden Anweisungen:

    select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update 
    insert into sequence_table (sequence_name, next_val) values (default,1) 
    update sequence_table set next_val=2 where next_val=1 and sequence_name=default 
    select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update 
    update sequence_table set next_val=3 where next_val=2 and sequence_name=default 
    select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update 
    update sequence_table set next_val=4 where next_val=3 and sequence_name=default 
    select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update 
    update sequence_table set next_val=5 where next_val=4 and sequence_name=default 
    select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update 
    update sequence_table set next_val=6 where next_val=5 and sequence_name=default 
    select identityvs0_.id as id1_0_0_ from assigneTableIdentifier identityvs0_ where identityvs0_.id=-1 
    insert into assigneTableIdentifier (id) values (1, 2) 
    insert into assigneTableIdentifier (id) values (2, 4) 
    insert into assigneTableIdentifier (id) values (5, -1) 
    

Für Oracle, können Sie die Reihenfolge kombinieren und die zugeordneten Generatoren wie in this article erläutert.

Kurz gesagt, die folgende Generator Berücksichtigung

public class AssignedSequenceStyleGenerator 
    extends SequenceStyleGenerator { 

    @Override 
    public Serializable generate(SessionImplementor session, 
     Object obj) { 
     if(obj instanceof Identifiable) { 
      Identifiable identifiable = (Identifiable) obj; 
      Serializable id = identifiable.getId(); 
      if(id != null) { 
       return id; 
      } 
     } 
     return super.generate(session, obj); 
    } 
} 

Sie können es auf Ihre Entitäten Karte wie folgt:

@Id 
@GenericGenerator(
    name = "assigned-sequence", 
    strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.AssignedSequenceStyleGenerator", 
    parameters = @org.hibernate.annotations.Parameter(
     name = "sequence_name", 
     value = "post_sequence" 
    ) 
) 
@GeneratedValue(
    generator = "assigned-sequence", 
    strategy = GenerationType.SEQUENCE 
) 
private Long id; 
2

versuchen, etwas wie folgt aus:

@Id 
@Column(name = "ID") 
@TableGenerator( 
     name = "AppSeqStore", 
     table = "APP_SEQ_STORE", 
     pkColumnName = "APP_SEQ_NAME", 
     pkColumnValue = "LISTENER_PK", 
     valueColumnName = "APP_SEQ_VALUE", 
     initialValue = 1, 
     allocationSize = 1) 
@GeneratedValue(strategy = GenerationType.TABLE, generator = "AppSeqStore") 

Und diese Tabelle in der Datenbank:

CREATE TABLE APP_SEQ_STORE (
    APP_SEQ_NAME VARCHAR(255) NOT NULL, 
    APP_SEQ_VALUE NUMBER(10) NOT NULL, 
    PRIMARY KEY(APP_SEQ_NAME) 
) 

INSERT INTO APP_SEQ_STORE VALUES ('LISTENER_PK', 0) 

Das alles funktioniert in Oracle und MS SQL Server und MySQL mit JBoss als Anwendungsserver.

Weitere Informationen hier: http://www.developerscrappad.com/408/java/java-ee/ejb3-jpa-3-ways-of-generating-primary-key-through-generatedvalue/

Verwandte Themen