Когда мое приложение теряет соединение, как мне его восстановить?

У меня есть приложение, которое я подключаю к базе данных MySQL. Он теряет связь в середине ночи, а затем извергает null Соединения и JDBC не получили сообщения в течение X секунд.

Я звоню getConnection() прежде чем делать что-либо, что требует связи с сервером SQL.

Это мое getConnection() метод:

private Connection getConnection() {
    try {
        if (connection != null) {
            if (connection.isClosed() || !connection.isValid(10000)) {
                this.initializeRamsesConnection();
            }
        } else {
            this.initializeRamsesConnection();
        }
    } catch (Exception e) {
        debug("Connection failed: " + e);
    }
    return connection;
}

в initializeRamsesConnection() Метод Я помещаю пароль и так далее информацию в строку, а затем я создаю соединение стандартным способом JDBC.

Затем я называю этот метод:

private Connection getConnectionFromConnectionString() {
    Connection con = null;
    String driver = "com.mysql.jdbc.Driver";
    try {
        Class.forName(driver);//jdbc sorcery
        //if there is no connection string
        if (getConnectionString() == null) {
            HMIDatabaseAdapter.debug("No connection string");
        }
        //makes a string out of the values of db/host
        String str = getConnectionString();
        //if there is no driver
        if (driver == null) {
            debug("" + ": " + "No driver");
        }
        //Tries to make a connection from the connection string, username, and the password.
        con = DriverManager.getConnection(str, username, password);
        //if for some reason the connection is null
        if (con == null) {
            HMIDatabaseAdapter.debug("CONNECTION IS NULL, WHAT?");
        }
    } catch (Exception ex) {
        HMIDatabaseAdapter.debug("getConnection() " + ex);
    }
    return con;
}

Что я могу изменить в любом из этих способов, чтобы приспособиться к потере соединения?

3 ответа

Решение

Это не правильный способ получения соединения. Вы извлекаете соединение и назначаете его в качестве экземпляра (или, что еще хуже, статической) переменной класса. По сути, вы сохраняете соединение открытым навсегда и повторно используете одно соединение для всех запросов. Это может привести к катастрофе, если запросы выполняются разными потоками. Кроме того, когда он остается открытым слишком долго, БД восстанавливает его, потому что предполагает, что он мертв / протек.

Вы должны приобрести и закрыть соединение в кратчайшие сроки. Т.е. в том же самом try блок, где вы выполняете запрос. Что-то вроде этого:

public Entity find(Long id) throws SQLException {
    Entity entity = null;

    try (
        Connection connection = dataSource.getConnection(); // This should return a NEW connection!
        PreparedStatement statement = connection.prepareStatement(SQL_FIND);
    ) {
        statement.setLong(1, id);

        try (ResultSet resultSet = preparedStatement.executeQuery()) {
            if (resultSet.next()) {
                entity = new Entity(
                    resultSet.getLong("id"),
                    resultSet.getString("name"),
                    resultSet.getInt("value")
                );
            }
        }
    }       

    return entity;
}

Если вы беспокоитесь о производительности соединения и хотите повторно использовать соединения, то вам следует использовать пул соединений. Вы могли бы доморощить один, но я настоятельно не одобряю это, поскольку вы, кажется, довольно плохо знакомы с материалом. Просто используйте существующий пул соединений, такой как BoneCP, C3P0 или DBCP. Обратите внимание, что вы не должны изменять идиому JDBC, как показано в примере выше. Вам все еще нужно приобрести и закрыть соединение в кратчайшие сроки. Пул соединений сам по себе будет беспокоиться о повторном использовании, тестировании и / или закрытии соединения.

Смотрите также:

Откуда в вашем коде возникают ошибки при потере соединения? Это, вероятно, будет лучшим местом для начала.

Сверху головы (и я могу ошибаться) соединения JDBC закроются только при реальной фатальной ошибке, поэтому вы не будете знать, что они потерпели неудачу, пока не попытаетесь что-то сделать.

В прошлом я делал недействительным соединение в точке сбоя и периодически повторял попытку.

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