2016-09-02 5 views
-1

Ich implementiere ein einfaches Jail-System für Minecraft-Server.
Jails sind Objekte, sie haben ihre eigene ID, Anzahl der Spieler innerhalb und Ort.Methode zum Erstellen eines Objekts, das Callback verwendet

Ich möchte eine einfache Methode zum Erstellen neuer Jail erstellen.

public static Jail createJail(final Location location); 

Diese Methode sollte automatisch neu erstellt Jail in DB einfügen meine DBhelper mit (was alles async läuft), und wenn etwas fehlschlägt, null zurück statt Jail Objekt. Das Problem ist natürlich bei CallBack und anonymer Klasse, die meine einfache CallBack-Schnittstelle implementieren, weil ich nichts innerhalb der inneren anonymen Klasse zurückgeben kann.

Hier ist, was ich bisher:

/** 
* Create new Jail object, fill with values and register in List 
* @param id Unique id of Jail, usually got from DB 
* @param location Location of Jail 
*/ 
private Jail(final int id, final Location location) { 
    this.id = id; 
    this.location = location; 
    this.amountOfJailed = 0; 
    jails.add(id, this); 
} 

/** 
* Tries to create new Jail<br /> 
* New Jail will be auto-inserted into DB. 
* @param location Valid Bukkit Location 
* @return Jail if successfully created, null otherwise 
*/ 
public static Jail createJail(final Location location) { 
    if (location == null) { 
     Bukkit.getLogger().warning(Lang.PREFIX + " Tried to create new Jail with invalid location"); 
     return null; 
    } 

    final Jail newJail; 

    DatabaseQuery db = new DatabaseQuery(); 
    db.insertJail(location, new SimpleCallBack() { 
     @Override 
     public void onQueryDone(ResultSet result) { 
      if (result == null) { 
       newJail = null; 
      } else { 
       result.next(); 
       int usedId = result.getInt("id"); 
       newJail = new Jail(usedId, location); 
      } 
     } 
    }); 

    return newJail; 
} 

und Databasequery # insertJail

/** 
* Inserts Jail into DB<br /> 
* When any error happens, callBack will receive null ResultSet<br /> 
* When everything goes well, ResultSet will hold generated id 
* @param location Location of inserted Jail 
* @param callBack Class with 'onQueryDone' method to be executed 
*/ 
public void insertJail(final Location location, final SimpleCallBack callBack) { 
    new BukkitRunnable() { 
     @Override 
     public void run() { 
      ResultSet result = null; 
      try 
      { 
       Connection connection = hikari.getConnection(); 
       PreparedStatement statement = connection.prepareStatement("INSERT INTO p_jails (`location`) VALUES (?);"); 
       statement.setString(1, Serializer.location_serialize(location)); 
       statement.executeUpdate(); 
       result = statement.getGeneratedKeys(); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      final ResultSet fResult = result; 
      new BukkitRunnable() { 
       @Override 
       public void run() { 
        callBack.onQueryDone(fResult); 
       } 
      }.runTask(Main.coreapi); 
     } 
    }.runTaskAsynchronously(Main.coreapi); 
} 

Wie soll ich createJail Methode implementieren? Ich muss wissen, ob es erfolgreich in DB eingefügt wurde, und ich muss id von ResultSet verwendet werden, damit ich dieses Jail-Objekt schließlich zurückgeben und ihm etwas wie "Erfolgreiches neues Gefängnis mit ID ##" sagen kann.

+0

Es ist nur sehr einfache Schnittstelle mit 'void onQueryDone (ResultSet result);' method –

+0

Weil das erste 'BukkitRunnable' es async macht. Dann rufe ich den Sync-Thread an, der manchmal von Bukkit als Tick-Thread bezeichnet wird.Wenn ich es auf zwei Methoden aufteile, wird es nicht helfen, weil ich 'Jail'-Objekt innerhalb der' createJail'-Methode zurückgeben muss ... aber nur, wenn es richtig in DB gespeichert ist. Diese Aufteilung würde nur aus einer Abfrage zwei Abfragen machen. Erst um freie ID zu bekommen und dann 'Jail' in DB zu speichern. –

Antwort

0

Siehe Antwort für sql jdbc getgeneratedkeys returns column "id" not found, column type unknown

Ich habe den Code von oben Antwort in diesem Thread entlehnt.

Nach result = statement.getGeneratedKeys(); müssen Sie die generierte ID aus der Ergebnismenge holen. Der Code wird wie folgt aussehen

int autoIncKeyFromApi = -1; 
rs = stmt.getGeneratedKeys(); 
if (rs.next()) { 
    autoIncKeyFromApi = rs.getInt(1); // "autoIncKeyFromApi" is th generated key 
    // Write the code to construct a Jail object here 
    Jail newJail = new Jail(); 
    newJail.setID(autoIncKeyFromApi); 
    // Set all other fields 
} else { 
    // Did not have a generated key either because no rows were inserted or yur query does not have a generated key column 
} 
System.out.println(autoIncKeyFromApi); 

Wenn Sie die SimpleCallBack Klasse selbst erstellt hat, ändern die Unterschrift der callBack.onQueryDone(fResult); ein Objekt von „Jail“ zu gelangen oder einer gemeinsamen übergeordneten Klasse aller Entitäten in Ihrem System. Der Rückruf wird wie folgt aussehen: 'callBack.onQueryDone (newJail);' . Beachten Sie, dass Rückrufe hauptsächlich mit Parametern und nicht mit Rückgabetypen arbeiten.

+0

Hallo, danke für die Antwort. Das Problem in dieser Frage empfängt keine Auto-Inkrement-ID von der DB, sondern gibt das erstellte Objekt mit dieser ID aus der Wrapping-Methode zurück. –

+0

OK, Entschuldigung, habe die Antwort aktualisiert –

+0

Wenn ich das Jail-Objekt selbst in CallBack übergebe, wie kann ich es aus der createJail-Methode zurückgeben? Es sollte nur zurückgegeben werden, wenn die DB-Abfrage erfolgreich abgeschlossen wurde. –

1

Sie sollten in Ihrem Code CompletableFuture verwenden. Ihre Methode sollte eine Signatur wie hat:

public static CompletableFuture<Jail> createJail(final Location location) 

Diese Methode Rückkehr sofort ein CompletableFuture für ein Gefängnis Objekt, das sie später zur Verfügung gestellt.

Sie können einfach eine CompletableFuture Instanz erstellen, und Sie können einfach einen Wert (Erfolg) oder eine Ausnahme (Fehler) darauf setzen. Legen Sie zum Beispiel die eingefügte Jail-Instanz fest, nachdem die Datenbank die Operation ausgeführt hat. Dazu finden Sie in die doc für Methoden complete() und completeExceptionnaly()

Dann fügen Sie einen (oder mehrere) Rückruf auf der komplettierbar Zukunft etwas bei Erfolg oder Misserfolg zu tun:

future.thenAccept(jail -> { /* do something */ }); 
future.exceptionnaly(exception -> { /* do something */ }); 
Verwandte Themen