我是Minecraft中服务器的开发人员,我们最近打开并经历了服务器崩溃(主机问题),这些崩溃导致许多玩家丢失了数据(在我们的主插件中),因为仅当他们登录时才会保存关。我想到了一种解决方案,但是当聊天中编写了2条以上的消息时,它将引发SQL异常,表明数据库已关闭。我们正在使用SQLite。
旧的注销保存方法。
我要为每个玩家登录时做的是从“玩家”表中选择所有列,并将所有信息放入HashMap中,因为服务器运行时,我会将数据获取/放入HashMap中,并且当玩家登录时关闭/服务器关闭,它将获取HashMap并将其放回到我们的SQLite文件中。
从SQLite到HashMap的代码
private void playerRecordToMap() throws SQLException
{
List<String> columnNames = getDB().queryColumnName(Statements.SELECT("Players", pUUID));
for (String column : columnNames)
{
if (!column.equals("UUID"))
{
System.out.println(column);
Object obj = getDB().queryValue(Statements.SELECT_COLUMN("Players", column, pUUID), column);
if (obj != null)
{
playerRecord.put(column, obj);
}
}
}
}
HashMap到SQLite
public void mapToPlayerRecord()
{
for (String s : playerRecord.keySet())
{
System.out.println(s);
getDB().executeStatement(Statements.UPDATE("Players", s, playerRecord.get(s).toString(), pUUID));
}
}
例如使用旧方法获取价值。
public Rank getRank()
{
int rankId = (int) playerRecord.get("RANK");
return Rank.fromId(rankId);
}
由于服务器多次崩溃,并且有可能在将来发生,所以我意识到,为了防止数据丢失,我应该直接与SQLite文件进行通信,但是当然会导致数据库关闭的SQLException。
新的保存方法
public Rank getRank()
{
String GET_RANK = Statements.SELECT("Players", pUUID);
int rankId = (int) getDB().queryValue(GET_RANK, "RANK");
return Rank.fromId(rankId);
}
public void setRank(int id)
{
String UPDATE_RANK = Statements.UPDATE("Players", "RANK", String.valueOf(id), pUUID);
getDB().executeStatement(UPDATE_RANK);
}
我已经检查了“ Statements”类中的所有语句方法,由于它们使用的是旧方法,因此它们没有问题。
只要玩家在聊天中写入多个消息,就会引发该异常(因为每条聊天消息都需要玩家的等级以及插件直接从SQLite文件中提取的其他信息)。
查询值和执行语句方法
public Boolean executeStatement(String statement)
{
Connection conn = null;
PreparedStatement ps = null;
try
{
conn = getConnection();
ps = conn.prepareStatement(statement);
return !ps.execute();
} catch (SQLException ex)
{
getLogger().log(Level.SEVERE, "can't execute", ex);
return false;
} finally
{
try
{
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (SQLException ex)
{
getLogger().log(Level.SEVERE, "can't close connection", ex);
return false;
}
}
}
public Object queryValue(String statement, String row)
{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = getConnection();
ps = conn.prepareStatement(statement);
rs = ps.executeQuery();
while (rs.next())
{
return rs.getObject(row);
}
} catch (SQLException ex)
{
getLogger().log(Level.SEVERE, "can't execute", ex);
} finally
{
try
{
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (SQLException ex)
{
getLogger().log(Level.SEVERE, "can't close connection", ex);
}
}
return null;
}
我的问题是: 解决上述情况的最佳方法是什么?如何做?
编辑: 奇怪的是,我已经在测试服务器上进行了多次测试,并且崩溃了,并且主机显示的错误非常相似,甚至是相同的错误,但是看起来却不像插件错误。
编辑2: 编辑1中的错误似乎是由SQLite引起的,因此使我们回到问题的解决方案是什么...