4 Stimmen

Hibernate mit Oracle 11g funktioniert nicht mit dem "select"-Generator

Ich verwende Hibernate 3.2.5 und Hibernate Annotations 3.3.1.GA als JPA-Anbieter in einer Datenladeanwendung. Ich habe Hibernate so konfiguriert, dass C3P0 für das Connection Pooling verwendet wird.

Meine Datenbank ist: Oracle Datenbank 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production

Da es keinen eingebauten Hibernate-Dialekt für 11g gibt, habe ich ihn so konfiguriert, dass er

org.hibernate.dialect.Oracle10gDialect

JDBC-Treiber: Oracle JDBC-Treiber, Version: 11.2.0.1.0

Die Anwendung lädt einige Transaktionsleistungsprotokolle von einem Mainframe-System in eine Oracle-DB zur späteren Analyse und Berichterstattung. Es handelt sich im Wesentlichen um einen Batch-Job, der einen Ordner überwacht und auf eine neue Datei wartet, die dann gelesen und in die Datenbank eingefügt wird (im Durchschnitt werden etwa 4,5 Millionen Zeilen pro Tag eingefügt). Daher habe ich mich für Hibernate entschieden, weil es JDBC-Batch-Inserts verwenden kann, die in EclipseLink nach einigen Vergleichstests nicht so gut zu funktionieren schienen. Die Dateien liegen in einem proprietären Binärformat vor, so dass ich einfachere Tools wie CSV-Importe usw. nicht verwenden kann.

Ursprünglich habe ich die Anwendung für die Verwendung mit MySQL auf meiner Workstation entwickelt, da sie ursprünglich für eine einmalige Analyseaufgabe gedacht war. Nun möchte ich sie auf eine unternehmensweite Oracle RAC-Plattform verschieben, da es sich als nützlich erwiesen hat, weiterhin Daten zu importieren und sie für einige Monate zur Verwendung durch mich und einige andere Analysten aufzubewahren. Ich habe die Tabellen von einem DBA konfigurieren lassen und meine Entitätsklassen so angepasst, dass sie einige geringfügige Änderungen in den Feldnamen und Datentypen widerspiegeln, und den Treiber und die Verbindungsdetails usw. geändert, aber ich bin auf einige Probleme mit der Primärschlüsselerzeugung gestoßen.

Es gibt einige Tabellen (Hauptdatentabelle mit einigen Tabellen, die verschiedene unterstützende Typen speichern, z. B. Transaktionsart, Nutzercodes usw.). Jede dieser Tabellen hat eine eindeutige (primäre) ID-Spalte, die mit Hilfe einer Sequenz und eines "Before-Update"-Triggers automatisch generiert wird.

Der DBA hat die Sequenzen so konfiguriert, dass sie von den Benutzern, die sie erstellt haben, nicht eingesehen werden können.

Die Verwendung der von JPA (javax.annotations) generierten Werttypen würde in keinem Fall funktionieren.

z. B:

@GeneratedValue(strategy = GenerationType.AUTO)

Dies ergibt das SQL:

select hibernate_sequence.nextval from dual

Der Oracle-Treiber löst eine Ausnahme mit der Fehlermeldung aus:

25/11/2009 11:57:23 AM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 2289, SQLState: 42000
25/11/2009 11:57:23 AM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: ORA-02289: sequence does not exist

Nachdem ich das herausgefunden hatte, recherchierte ich ein wenig und fand die Möglichkeit, die Hibernate JPA Annotation Extensions "GenericGenerator" mit einer "select"-Strategie zu verwenden ( http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping.html#mapping-declaration-id-generator )

z.B.

@GeneratedValue(generator="id_anEntity")
@GenericGenerator(name = "id_anEntity",
strategy = "select")

Wenn ich dies jedoch verwende, stelle ich fest, dass Hibernate während der Erstellung von EntityManagerFactory hängen bleibt. Es scheint über den Aufbau der Eigenschaften, den Aufbau der benannten Abfragen und die Verbindung zum Server hinauszugehen, und bleibt dann bei hängen:

25/11/2009 1:40:50 PM org.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory

und kehrt nicht zurück.

Ich habe festgestellt, dass das Gleiche passiert, wenn ich den Dialekt nicht in der Datei persistence.xml angegeben habe.

Es funktioniert gut, wenn ich die "Inkrement"-Strategie verwende, obwohl dies bedeutet, dass die Sequenzen dann unterbrochen werden, da der Wert erhöht wurde, ohne dass die Sequenz erhöht wurde, was weniger als ideal ist.

Die "native" Strategie ergibt die gleiche Ausgabe wie die Verwendung von GenerationType.AUTO (ORA-02289: Sequenz existiert nicht).

Ich bin mir nicht sicher, ob dies daran liegt, dass ich die falsche Schlüsselgenerierungsstrategie verwende, oder an einem Fehler in meiner Konfiguration oder an einem Bug.

Jede Hilfe, um die "select"-Strategie zum Laufen zu bringen, oder eine bessere Alternative ist sehr willkommen. Ich könnte möglicherweise zurück zu reinen JDBC mit vorbereiteten Anweisungen und so gehen, aber dies neigt dazu, ein wenig chaotisch zu bekommen und ich bevorzuge den JPA-Ansatz.

Einige weitere Informationen:

Persistence.xml-Eigenschaften:

        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.c3p0.min_size" value="5"/>
        <property name="hibernate.c3p0.max_size" value="20"/>
        <property name="hibernate.c3p0.timeout" value="1800"/>
        <property name="hibernate.c3p0.max_statements" value="100000"/>
        <property name="hibernate.jdbc.use_get_generated_keys" value="true"/>
        <property name="hibernate.cache.use_query_cache" value="false"/>
        <property name="hibernate.cache.use_second_level_cache" value="false"/>
        <property name="hibernate.order_inserts" value="true"/>
        <property name="hibernate.order_updates" value="true"/>
        <property name="hibernate.connection.username" value="myusername"/>
        <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
        <property name="hibernate.connection.password" value="mypassword"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
        <property name="hibernate.connection.url" value="jdbc:oracle:thin:@(DESCRIPTION =
    (ADDRESS      = (PROTOCOL = TCP) (HOST = myoracleserver) (PORT = 1521))
    (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = myservicename))
  )"/>
        <property name="hibernate.jdbc.batch_size" value = "100000" />

Ein Beispiel für die Deklaration des ID-Feldes in einer der Entitätsklassen unter Verwendung von Annotationen:

@Entity
@Table(name = "myentity",
catalog = "",
schema = "mydb")
public class myEntity implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @GeneratedValue(generator="id_anEntity")
    @GenericGenerator(name = "id_anEntity",
    strategy = "select")
    @Column(name = "MYENTITYID",
    nullable = false)
    private Integer myEntityID;

   //... other column mappings

    public Integer getMyEntityID() {
        return myEntityID;
    }

    public void setMyEntityID(Integer myEntityID) {
        this. myEntityID = myEntityID;
    }

   //... other getters & setters
}

2voto

ChssPly76 Punkte 97241

Mir ist nicht ganz klar, was Sie mit "Der DBA hat die Sequenzen so konfiguriert, dass sie für die Benutzer, die sie erstellt haben, nicht sichtbar sind" meinen. - Heißt das, dass die Sequenz für Sie nicht sichtbar ist? Warum nicht?

Um einen sequenzbasierten Generator zu verwenden, bei dem der Name der Sequenz nicht "hibernate_sequence" lautet (was im wirklichen Leben nie der Fall ist; dies ist nur die Standardeinstellung), müssen Sie den entsprechenden Generator angeben :

@SequenceGenerator(name="myentity_seq", sequenceName="my_sequence")
public class MyEntity {
 ...

 @Id
 @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="myentity_seq")
 private Integer myEntityID;
 ...
}

"select"-Generatorstrategie bedeutet, dass Hibernate versucht, die soeben eingefügte Zeile anhand eines eindeutigen Schlüssels auszuwählen (natürlich ein anderer als PK). Haben Sie das definiert? Ich würde stark Ich schlage vor, dass Sie stattdessen die Sequenz verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X