SQL 结果集突然关闭
SQL ResultSet closing suddently
您好 Whosebug 用户,
目前我的 SQL 连接出现问题。首先,这里是连接器的处理方式
package com.rs.utils.sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import com.rs.utils.Logger;
public class DatabaseManager {
private String host;
private String database;
private String username;
private String password;
private Connection connection;
private PreparedStatement statement;
private boolean connected;
public DatabaseManager() {
this.host = "";// Settings.DB_HOST;
this.database = "";// Settings.DB_NAME;
this.username = "";// Settings.DB_USER;
this.password = "";// Settings.DB_PASS;
this.connected = false;
}
public void connect() {
try {
connection = DriverManager.getConnection("jdbc:mysql://" + host
+ "/" + database
+ "?jdbcCompliantTruncation=false&autoReconnect=true",
username, password);
Logger.info("Successfully connected with " + host + "/" + database);
connected = true;
} catch (Exception e) {
Logger.info("Unable to connect with " + host + "/" + database + ".");
connected = false;
}
}
public ResultSet executeQuery(String query) {
try {
if (!connected())
return null;
statement = connection.prepareStatement(query);
ResultSet results = statement.executeQuery();
return results;
} catch (Exception e) {
Logger.handle(e);
}
return null;
}
public int executeUpdate(String query) {
try {
if (!connected())
return 0;
statement = connection.prepareStatement(query);
return statement.executeUpdate();
} catch (Exception e) {
Logger.handle(e);
}
return 0;
}
public boolean connected() {
return connected;
}
public PreparedStatement statement() {
return statement;
}
}
使用 DatabaseManager 实例向数据库发送大量查询,例如:
databaseManager.executeUpdate(query);
databaseManager 定义为:
private static DatabaseManager databaseManager = new DatabaseManager();
我得到以下 Throwable:
java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:988)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:974)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:919)
at com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:803)
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1126)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5732)
at com.rs.utils.sql.PlayerSaving.load(PlayerSaving.java:362)
at com.rs.utils.sql.PlayerLoader.load(PlayerLoader.java:90)
PlayerLoader 中的加载方法:
public static boolean load(Player player, boolean lobby) {
ResultSet result = null;
try {
final long current = System.currentTimeMillis();
result = World.database().executeQuery("SELECT " + (lobby ? "displayName, rights" : "*") + " FROM " + PLAYER_TABLE + " WHERE username='" + player.getPlayerDefinition().username() + "' LIMIT 1");
if (!result.next()) {
return false;
}
if (lobby) {
player.getPlayerDefinition().setRights(result.getInt("rights")).setDisplayName(result.getString("displayName"));
} else {
**player.playerSaving().load(result);**
}
Logger.log("Loader", "Player loaded in " + (System.currentTimeMillis() - current) + "ms.");
return true;
} catch (Exception e) {
Logger.log("Loader", "Unable to load player profile.");
Logger.handle(e);
System.err.println("Error Loading the account.");
} finally {
try {
if (result != null) {
result.close();
}
result = null;
World.database().statement().close();
} catch (SQLException e) {
Logger.handle(e);
}
}
return false;
}
PlayerSaving 加载方法只是将数据库中的值分配给另一个 class 实例 result.getInt("rowName") 等,在 ResultSet 上收到,它超过 250 行
ResultSet 大多数时候都很好,这是非常罕见的事件,例如 100 次登录尝试中只有 1 次。但是不知何故 ResultSet 在变量赋值的中间关闭了,比如,它分配了 200 个变量中的 100 个,然后 ResultSet 突然关闭并抛出异常。
有什么想法吗?
关闭语句也将关闭底层 ResultSet。您可能对只有一个共享 PreparedStatement 的 DatabaseManager 进行了嵌套调用,在我看来,这是个坏主意。
(我没有足够的代表来添加评论,所以我不得不 post 这个作为答案)
下面是为每个查询操作使用专用 PreparedStatement 和 ResultSet 的示例实现:
public List<MyDataClass> listMyData(Connection con, String partNumber) {
ArrayList<MyDataClass> list = new ArrayList<MyDataClass>();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = con.prepareStatement("SELECT PART_NO, DESC, PRICE FROM MYTABLE WHERE PART_NO = ?");
ps.setString(1, partNumber);
rs = ps.executeQuery();
while(rs.next()) {
MyDataClass myData = new MyDataClass();
myData.setPartNumber(rs.getString("PART_NO"));
myData.setDescription(rs.getString("DESC"));
myData.setPrice(rs.getBigDecimal("PRICE"));
list.add(myData);
}
con.commit();
}
catch(Throwable thrown) {
try{ con.rollback(); }catch(Throwable t){}
//Handle the exception here to log etc.
}
finally {
//Always close result set before statement
if(rs != null) { try{ rs.close(); }catch(Throwable t){} }
if(ps != null) { try{ ps.close(); }catch(Throwable t){} }
}
return list;
}
您好 Whosebug 用户,
目前我的 SQL 连接出现问题。首先,这里是连接器的处理方式
package com.rs.utils.sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import com.rs.utils.Logger;
public class DatabaseManager {
private String host;
private String database;
private String username;
private String password;
private Connection connection;
private PreparedStatement statement;
private boolean connected;
public DatabaseManager() {
this.host = "";// Settings.DB_HOST;
this.database = "";// Settings.DB_NAME;
this.username = "";// Settings.DB_USER;
this.password = "";// Settings.DB_PASS;
this.connected = false;
}
public void connect() {
try {
connection = DriverManager.getConnection("jdbc:mysql://" + host
+ "/" + database
+ "?jdbcCompliantTruncation=false&autoReconnect=true",
username, password);
Logger.info("Successfully connected with " + host + "/" + database);
connected = true;
} catch (Exception e) {
Logger.info("Unable to connect with " + host + "/" + database + ".");
connected = false;
}
}
public ResultSet executeQuery(String query) {
try {
if (!connected())
return null;
statement = connection.prepareStatement(query);
ResultSet results = statement.executeQuery();
return results;
} catch (Exception e) {
Logger.handle(e);
}
return null;
}
public int executeUpdate(String query) {
try {
if (!connected())
return 0;
statement = connection.prepareStatement(query);
return statement.executeUpdate();
} catch (Exception e) {
Logger.handle(e);
}
return 0;
}
public boolean connected() {
return connected;
}
public PreparedStatement statement() {
return statement;
}
}
使用 DatabaseManager 实例向数据库发送大量查询,例如:
databaseManager.executeUpdate(query);
databaseManager 定义为:
private static DatabaseManager databaseManager = new DatabaseManager();
我得到以下 Throwable:
java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:988)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:974)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:919)
at com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:803)
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1126)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5732)
at com.rs.utils.sql.PlayerSaving.load(PlayerSaving.java:362)
at com.rs.utils.sql.PlayerLoader.load(PlayerLoader.java:90)
PlayerLoader 中的加载方法:
public static boolean load(Player player, boolean lobby) {
ResultSet result = null;
try {
final long current = System.currentTimeMillis();
result = World.database().executeQuery("SELECT " + (lobby ? "displayName, rights" : "*") + " FROM " + PLAYER_TABLE + " WHERE username='" + player.getPlayerDefinition().username() + "' LIMIT 1");
if (!result.next()) {
return false;
}
if (lobby) {
player.getPlayerDefinition().setRights(result.getInt("rights")).setDisplayName(result.getString("displayName"));
} else {
**player.playerSaving().load(result);**
}
Logger.log("Loader", "Player loaded in " + (System.currentTimeMillis() - current) + "ms.");
return true;
} catch (Exception e) {
Logger.log("Loader", "Unable to load player profile.");
Logger.handle(e);
System.err.println("Error Loading the account.");
} finally {
try {
if (result != null) {
result.close();
}
result = null;
World.database().statement().close();
} catch (SQLException e) {
Logger.handle(e);
}
}
return false;
}
PlayerSaving 加载方法只是将数据库中的值分配给另一个 class 实例 result.getInt("rowName") 等,在 ResultSet 上收到,它超过 250 行
ResultSet 大多数时候都很好,这是非常罕见的事件,例如 100 次登录尝试中只有 1 次。但是不知何故 ResultSet 在变量赋值的中间关闭了,比如,它分配了 200 个变量中的 100 个,然后 ResultSet 突然关闭并抛出异常。
有什么想法吗?
关闭语句也将关闭底层 ResultSet。您可能对只有一个共享 PreparedStatement 的 DatabaseManager 进行了嵌套调用,在我看来,这是个坏主意。
(我没有足够的代表来添加评论,所以我不得不 post 这个作为答案)
下面是为每个查询操作使用专用 PreparedStatement 和 ResultSet 的示例实现:
public List<MyDataClass> listMyData(Connection con, String partNumber) {
ArrayList<MyDataClass> list = new ArrayList<MyDataClass>();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = con.prepareStatement("SELECT PART_NO, DESC, PRICE FROM MYTABLE WHERE PART_NO = ?");
ps.setString(1, partNumber);
rs = ps.executeQuery();
while(rs.next()) {
MyDataClass myData = new MyDataClass();
myData.setPartNumber(rs.getString("PART_NO"));
myData.setDescription(rs.getString("DESC"));
myData.setPrice(rs.getBigDecimal("PRICE"));
list.add(myData);
}
con.commit();
}
catch(Throwable thrown) {
try{ con.rollback(); }catch(Throwable t){}
//Handle the exception here to log etc.
}
finally {
//Always close result set before statement
if(rs != null) { try{ rs.close(); }catch(Throwable t){} }
if(ps != null) { try{ ps.close(); }catch(Throwable t){} }
}
return list;
}