我正在为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”。
答案 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; 。请注意,回调主要使用参数而不是返回类型。