2017-12-20 8 views
0

Ich habe ein Problem mit dem Einfügen neuer Zeilen in meine MySQL-Datenbank. Ich verwende Spring Boot mit Spring Boot Data JPA.Hibernate nach dem Einfügen auswählen

Da MySQL keine Sequenzen unterstützt, entschied ich mich, meine eigene Sequenzgenerator-Tabelle zu erstellen. Das ist im Grunde, was ich getan habe.

  1. Ich erstellte eine sequences Tabelle, die ein Autoinkrementfeld verwendet (als meine ID für meine Tabellen verwendet).
  2. Eine Funktion sequences_nextvalue() erstellt, die in die Tabelle sequences eingefügt wird und die neue automatisch inkrementierte ID zurückgibt.
  3. Ich erstellte dann Trigger für jede Tabelle, die vor dem Einfügen ausgelöst werden und ersetzt das ID-Feld mit dem Ergebnis des Aufrufs sequences_nextvalue().

Das funktioniert also gut beim Einfügen neuer Zeilen. Ich bekomme einzigartige IDs über alle Tabellen. Das Problem, das ich habe, ist mit meinen JPA-Entitäten.

@Entity 
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 
public abstract class AbstractBaseClass { 
    @Id 
    private Integer id = -1; 
    ... 
} 

@Entity 
public class ConcreteClass1 extends AbstractBaseClass { 
    ... 
} 


@Entity 
public class ConcreteClass2 extends AbstractBaseClass { 
    ... 
} 

Ich möchte von der abstrakten Basisklasse abfragen können, so dass ich meine @Id Spalte in dieser Klasse platziert haben und verwendet @Entity mit InheritanceType.TABLE_PER_CLASS. Ich habe auch die ID auf -1 initialisiert, da eine ID erforderlich ist, um save() von meinem Spring Crud Repository aufzurufen.

die save() Funktion meiner Frühjahrsdaten Nach dem Aufruf von CrudRepository, die -1 für id richtig durch den Trigger MySQL ersetzt wird, aber die resultierende durch save() zurück Einheit nicht zurück mit dem neuen id sondern behält stattdessen die -1. Nachdem Sie sich die SQL-Protokolle angesehen haben, wird nach dem Einfügen keine SELECT-Anweisung aufgerufen, um die neue ID abzurufen, stattdessen wird die ursprüngliche Entität zurückgegeben.

Ist es möglich, Hibnerate zu zwingen, die Entität nach dem Einfügen erneut auszuwählen, um die neue ID zu erhalten, wenn Sie nicht @GeneratedValue verwenden?

Jede Hilfe wird sehr geschätzt.

+0

MySQL unterstützt Sequence..https: //stackoverflow.com/questions/26578313/how-do-i-create-a-sequence-in-mysql – Yogi

+0

die Problem mit AUTO_INCREMENT ist, dass der Bereich so definiert ist, dass jede Tabelle ihr eigenes "AUTO_INCREMENT" -Feld hat, das überlappende IDs erlaubt. Ich möchte eindeutige IDs über mehrere Tabellen haben, was bedeutet, wenn ich ID 1 in "SOME_TABLE" habe, wird es keine ID von 1 in "ANOTHER_TABLE" geben. Also im Grunde möchte ich mehrere Tabellen teilen und 'AUTO_INCREMENT' Feld. – jmw5598

+0

Ich habe bereits funktioniert, aber da ich '@ GeneratedValue' nicht verwende, führt Hibernate nicht das' SELECT' aus, das es normalerweise nach 'INSERT' durchführt, also bekomme ich die neu generierte ID nicht in der zurückgegebenen Entity auf' save() '. Die ID wird jedoch ordnungsgemäß in der Datenbank gespeichert. – jmw5598

Antwort

0

Ich wollte nur ein Update zu dieser Frage bereitstellen. Hier ist meine Lösung.

Statt Erstellung MySQL TRIGGER ist die id auf INSERT zu ersetzen, habe ich eine Hibernate IdentifierGenerator, die ein CallableStatement führt eine neue ID zu bekommen und zurück.

Meine abstrakte Basisklasse sieht jetzt so aus.

@Entity 
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 
public abstract class AbstractBaseClass { 

    @Id 
    @GenericGenerator(name="MyIdGenerator", strategy="com.sample.model.CustomIdGenerator") 
    @GeneratedValue(generator="MyIdGenerator") 
    private Integer id; 
    ... 

} 

und mein Generator sieht so aus.

public class CustomIdGenerator implements IdentifierGenerator { 

    private Logger log = LoggerFactory.getLogger(CustomIdGenerator.class); 
    private static final String QUERY = "{? = call sequence_nextvalue()}"; 

    @Override 
    public Serializable generate(SessionImplementor session, Object object) throws HibernateException { 

     Integer id = null; 
     try { 
      Connection connection = session.connection(); 
      CallableStatement statement = connection.prepareCall(QUERY); 
      statement.registerOutParameter(1, java.sql.Types.INTEGER); 
      statement.execute(); 
      id = statement.getInt(1); 
     } catch(SQLException e) { 
      log.error("Error getting id", e); 
      throw new HibernateException(e); 
     } 
     return id; 
    } 

} 

Und gerade als Referenz

Die sequences Tisch.

CREATE TABLE sequences (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    thread_id INT NOT NULL, 
    created DATETIME DEFAULT CURRENT_TIMESTAMP 
) ^; 

Die Funktion sequence_nextvalue

CREATE FUNCTION sequence_nextvalue() 
RETURNS INTEGER 
NOT DETERMINISTIC 
MODIFIES SQL DATA 
BEGIN 
    DECLARE nextvalue INTEGER; 
    INSERT INTO sequences (thread_id) VALUE (CONNECTION_ID()); 
    SELECT id FROM sequence_values ORDER BY created DESC LIMIT 1 INTO nextvalue; 
    RETURN nextvalue; 
END ^; 
Verwandte Themen