创建使用回调的对象的方法

时间:2016-09-02 12:17:18

标签: java mysql asynchronous callback bukkit

我正在为Minecraft服务器实现简单的Jail系统 Jails是对象,它们有自己的id,内部和位置的玩家数量。

我想创建一个简单的方法来创建新的Jail。

public static Jail createJail(final Location location);

此方法应使用我的DBhelper(运行所有异步)自动将新创建的Jail插入到DB中,如果出现故障,则返回null而不是Jail对象。问题当然是callBack和匿名类实现我的简单CallBack接口,因为我无法在内部匿名类中返回任何内容。

这是我到目前为止所做的:

/**
 * 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;
}

和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);
}

我应该如何实施方法createJail?我需要知道它是否已成功插入到DB中,我需要从ResultSet中获取id,这样我最终可以返回该Jail对象并告诉他“使用ID ##成功创建新Jail”。

2 个答案:

答案 0 :(得分:1)

您应该考虑在代码中使用CompletableFuture。您的方法应该具有以下签名:

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

此方法立即为Jail对象返回CompletableFuture,稍后将可用。

您可以轻松创建CompletableFuture实例,并且可以轻松地在其上设置值(成功)或异常(失败)。例如,在数据库执行操作后设置插入的jail实例。为此,请参阅方法complete()completeExceptionnaly()

的文档

然后,在可完成的未来上添加一个(或几个)回调,以便在成功或失败时执行某些操作:

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

答案 1 :(得分:0)

查看sql jdbc getgeneratedkeys returns column "id" not found, column type unknown

的答案

我从这个帖子的顶部答案中借用了代码。

result = statement.getGeneratedKeys();之后,您需要从结果集中获取生成的ID。代码看起来像

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);

如果您自己创建了SimpleCallBack类,请更改callBack.onQueryDone(fResult);的签名以传递&#34; Jail&#34;的对象。或系统中所有实体的公共超类。回拨将看起来像callBack.onQueryDone(newJail);&#39; 。请注意,回调主要使用参数而不是返回类型。