MYSQL JDBC java.sql.SQLException: операция не разрешена после закрытия ResultSet

У меня есть программа, которая запрашивает базу данных с использованием разных драйверов 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;
    }
}

вы должны закрыть соединение в "окончательном блоке"

isaace 10.04.2018 17:39

Я попытался переместить conn.close () в блок finally под моим блоком try, но он дает ту же самую ошибку.

Salvador Martinez 10.04.2018 17:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
317
1

Ответы 1

Проблема в том, что вы пытаетесь получить доступ к ResultSet после закрытия connection.

Вы должны открывать и закрывать соединение в методе, вызывающем run(), таким образом, соединение будет открыто, когда вы получите доступ к Resultset и закроете его в блоке finally вызывающего метода.

Еще лучше было бы, если бы вы могли просто пройти через ResultSet в методе run(), добавить данные в object и вернуть object, таким образом вы можете закрыть его в блоке finally метода run().

Но разве соединение не закрывается автоматически? У меня эта программа работает с интервалами, и каждую минуту она будет запрашивать из базы данных. Спустя 10 минут я все еще вижу менее 3 подключений от пользователя в рабочей среде MySQL.

Salvador Martinez 10.04.2018 18:22

Не уверен, о чем вы здесь спрашиваете. Имейте в виду, что вы не можете прочитать ResultSet после закрытия соединения.

isaace 10.04.2018 18:24

также см. stackoverflow.com/questions/25864235/…

isaace 10.04.2018 18:30

Когда я запускаю тот же код с помощью драйвера psql jdbc, я не получаю ту же ошибку. Больше ничего не изменилось, кроме строки подключения и имени класса.

Salvador Martinez 10.04.2018 20:31

возможно, что для postgresql есть кеширование, я не уверен.

isaace 10.04.2018 20:45

Другие вопросы по теме