У меня есть программа, которая запрашивает базу данных с использованием разных драйверов jdbc. Эта ошибка специфична для драйвера MySQL.
Вот краткое изложение.
У меня есть еще один класс обработчика запросов, который использует драйвер postgresql jdbc, который отлично работает. Обратите внимание на строку conn.close (); это отлично работает на моем средстве выполнения запросов postgresql, но для этого средства выполнения запросов SQL возникает ошибка.
Я удалил строку conn.close (); и этот код работает нормально, но со временем он накапливает спящие соединения в базе данных. Как я могу это исправить?
New Relic - это стороннее приложение, в которое я загружаю данные, если вы не знаете, что это такое, не волнуйтесь, это не очень важно для этой ошибки.
ГЛАВНЫЙ КЛАСС
public class JavaPlugin {
public static void main(String[] args) {
try {
Runner runner = new Runner();
runner.add(new MonitorAgentFactory());
runner.setupAndRun(); // never returns
}
catch (ConfigurationException e) {
System.err.println("ERROR: " + e.getMessage());
System.exit(-1);
}
catch (Exception e) {
System.err.println("ERROR: " + e.getMessage());
System.exit(-1);
}
}
}
КЛАСС ЗАПРОСОВ MYSQL
import com.newrelic.metrics.publish.util.Logger;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;
public class MySQLQueryRunner {
private static final Logger logger = Logger.getLogger(MySQLQueryRunner.class);
private String connectionStr;
private String username;
private String password;
public MySQLQueryRunner(String host, long port, String database, String username, String password) {
this.connectionStr = "jdbc:mysql://" + host + ":" + port + "/" + database + "?useSSL=false";
this.username = username;
this.password = password;
}
private void logError(String message) {
logger.error(new Object[]{message});
}
private void logDebugger(String message) {
logger.debug(new Object[]{message});
}
private Connection establishConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
logError("MySQL Driver could not be found");
e.printStackTrace();
return null;
}
Connection connection = null;
try {
connection = DriverManager.getConnection(connectionStr, username, password);
logDebugger("Connection established: " + connectionStr + " using " + username);
} catch (SQLException e) {
logError("Connection Failed! Check output console");
e.printStackTrace();
return null;
}
return connection;
}
public ResultSet run(String query) {
Connection conn = establishConnection();
if (conn == null) {
logError("Connection could not be established");
return null;
}
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
conn.close();
return rs;
} catch (SQLException e) {
logError("Failed to collect data from database");
e.printStackTrace();
return null;
}
}
}
АГЕНТ КЛАСС
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import com.newrelic.metrics.publish.Agent;
public class LocalAgent extends Agent {
private MySQLQueryRunner queryRunner;
private String name;
private Map<String, Object> thresholds;
private int intervalDuration;
private int intervalCount;
public LocalAgent(String name, String host, long port, String database, String username, String password, Map<String, Object> thresholds, int intervalDuration) {
super("com.mbt.local", "1.0.0");
this.name = name;
this.queryRunner = new MySQLQueryRunner(host, port, database, username, password);
// this.eventPusher = new NewRelicEvent();
this.thresholds = thresholds;
this.intervalDuration = intervalDuration;
this.intervalCount = 0;
}
/**
* Description of query
*/
private void eventTestOne() {
String query = "select count(1) as jerky from information_schema.tables;";
ResultSet rs = queryRunner.run(query);
try {
while (rs.next()) {
NewRelicEvent event = new NewRelicEvent("localTestOne");
event.add("jerky", rs.getInt("jerky"));
event.push();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* blah
*/
private void eventTestTwo() {
String query = "SELECT maxlen FROM information_schema.CHARACTER_SETS;";
ResultSet rs = queryRunner.run(query);
try {
while (rs.next()) {
NewRelicEvent event = new NewRelicEvent("localTestTwo");
event.add("beef", rs.getString("maxlen"));
event.push();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void pollCycle() {
if (this.intervalCount % this.intervalDuration == 0) {
eventTestOne();
eventTestTwo();
this.intervalCount = 0;
}
// Always incrementing intervalCount, keeping track of poll cycles that have passed
this.intervalCount++;
}
@Override
public String getAgentName() {
return this.name;
}
}
Я попытался переместить conn.close () в блок finally под моим блоком try, но он дает ту же самую ошибку.




Проблема в том, что вы пытаетесь получить доступ к ResultSet после закрытия connection.
Вы должны открывать и закрывать соединение в методе, вызывающем run(), таким образом, соединение будет открыто, когда вы получите доступ к Resultset и закроете его в блоке finally вызывающего метода.
Еще лучше было бы, если бы вы могли просто пройти через ResultSet в методе run(), добавить данные в object и вернуть object, таким образом вы можете закрыть его в блоке finally метода run().
Но разве соединение не закрывается автоматически? У меня эта программа работает с интервалами, и каждую минуту она будет запрашивать из базы данных. Спустя 10 минут я все еще вижу менее 3 подключений от пользователя в рабочей среде MySQL.
Не уверен, о чем вы здесь спрашиваете. Имейте в виду, что вы не можете прочитать ResultSet после закрытия соединения.
также см. stackoverflow.com/questions/25864235/…
Когда я запускаю тот же код с помощью драйвера psql jdbc, я не получаю ту же ошибку. Больше ничего не изменилось, кроме строки подключения и имени класса.
возможно, что для postgresql есть кеширование, я не уверен.
вы должны закрыть соединение в "окончательном блоке"